package me.khodak.claudeusage.data

import android.content.Context
import androidx.security.crypto.EncryptedSharedPreferences
import androidx.security.crypto.MasterKey
import com.google.gson.Gson
import java.util.Calendar

class PreferencesManager(context: Context) {

    private val gson = Gson()

    private var usingFallbackPrefs = false
    private val securePrefs = createSecurePrefs(context, onFallback = { usingFallbackPrefs = true })

    private val prefs = context.getSharedPreferences("claude_prefs", Context.MODE_PRIVATE)

    fun saveCookies(cookies: String) {
        // Never store cookies in plain-text fallback prefs
        if (usingFallbackPrefs) return
        try {
            securePrefs.edit().putString(KEY_COOKIES, cookies).apply()
        } catch (_: Exception) {}
    }

    fun getCookies(): String? = try {
        securePrefs.getString(KEY_COOKIES, null)
    } catch (_: Exception) { null }

    fun clearSession() {
        try { securePrefs.edit().clear().apply() } catch (_: Exception) {}
        prefs.edit().remove(KEY_ORG_ID).remove(KEY_SESSION_START).apply()
    }

    fun saveOrgId(id: String) = prefs.edit().putString(KEY_ORG_ID, id).apply()
    fun getOrgId(): String? = prefs.getString(KEY_ORG_ID, null)

    fun saveSessionStart(epochMs: Long) = prefs.edit().putLong(KEY_SESSION_START, epochMs).apply()
    fun getSessionStart(): Long = prefs.getLong(KEY_SESSION_START, 0L)

    fun markTodayActive() {
        val cal = Calendar.getInstance()
        val dayBit = 1 shl cal.get(Calendar.DAY_OF_WEEK) - 1
        val weekKey = getWeekKey(cal)
        // Reset mask if it's a new week
        val storedWeek = prefs.getString(KEY_ACTIVE_WEEK, "")
        val currentMask = if (storedWeek == weekKey) prefs.getInt(KEY_ACTIVE_MASK, 0) else 0
        prefs.edit()
            .putString(KEY_ACTIVE_WEEK, weekKey)
            .putInt(KEY_ACTIVE_MASK, currentMask or dayBit)
            .apply()
    }

    fun getWeeklyMask(): Int {
        val cal = Calendar.getInstance()
        val weekKey = getWeekKey(cal)
        val storedWeek = prefs.getString(KEY_ACTIVE_WEEK, "")
        return if (storedWeek == weekKey) prefs.getInt(KEY_ACTIVE_MASK, 0) else 0
    }

    private fun getWeekKey(cal: Calendar): String {
        val year = cal.get(Calendar.YEAR)
        val week = cal.get(Calendar.WEEK_OF_YEAR)
        return "$year-$week"
    }

    fun saveUsageData(data: UsageData) =
        prefs.edit().putString(KEY_USAGE_DATA, gson.toJson(data)).apply()

    fun getUsageData(): UsageData? = try {
        prefs.getString(KEY_USAGE_DATA, null)?.let { gson.fromJson(it, UsageData::class.java) }
    } catch (e: Exception) { null }

    fun isLoggedIn(): Boolean = !getCookies().isNullOrBlank()

    companion object {
        private const val KEY_COOKIES = "session_cookies"
        private const val KEY_ORG_ID = "org_id"
        private const val KEY_SESSION_START = "session_start"
        private const val KEY_USAGE_DATA = "usage_data"
        private const val KEY_ACTIVE_WEEK = "active_week"
        private const val KEY_ACTIVE_MASK = "active_mask"

        fun createSecurePrefs(context: Context, onFallback: (() -> Unit)? = null): android.content.SharedPreferences {
            return try {
                buildEncryptedPrefs(context)
            } catch (e: Exception) {
                if (isKeyPermanentlyInvalidated(e)) {
                    // Key permanently gone (biometric/PIN changed) — must wipe; user must re-login.
                    try {
                        context.deleteSharedPreferences("claude_secure")
                        buildEncryptedPrefs(context)
                    } catch (_: Exception) {
                        onFallback?.invoke()
                        context.getSharedPreferences("claude_secure_fallback", Context.MODE_PRIVATE)
                    }
                } else {
                    // Transient failure (Keystore busy, cold boot, screen locked during BG work).
                    // Do NOT delete the encrypted file — it will be readable next session.
                    onFallback?.invoke()
                    context.getSharedPreferences("claude_secure_fallback", Context.MODE_PRIVATE)
                }
            }
        }

        private fun buildEncryptedPrefs(context: Context): android.content.SharedPreferences {
            val masterKey = MasterKey.Builder(context)
                .setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
                .build()
            return EncryptedSharedPreferences.create(
                context, "claude_secure", masterKey,
                EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
                EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
            )
        }

        private fun isKeyPermanentlyInvalidated(e: Exception): Boolean {
            var t: Throwable? = e
            while (t != null) {
                if (t is android.security.keystore.KeyPermanentlyInvalidatedException) return true
                t = t.cause
            }
            return false
        }
    }
}
