package com.tomhempel.rbarometer.network

import android.content.Context
import android.util.Log
import androidx.security.crypto.EncryptedSharedPreferences
import androidx.security.crypto.MasterKey

object TokenStore {
    private const val TAG = "TokenStore"
    private const val PREF = "qdb_secure_prefs"
    private const val KEY_TOKEN = "token"
    private const val KEY_USER = "user"
    private const val KEY_LOGIN_TS = "login_ts"

    private const val SESSION_TTL_MS = 30L * 24 * 60 * 60 * 1000

    private fun prefs(context: Context) = EncryptedSharedPreferences.create(
        context,
        PREF,
        MasterKey.Builder(context)
            .setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
            .build(),
        EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
        EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM,
    )

    fun save(context: Context, token: String, username: String) {
        val now = System.currentTimeMillis()
        prefs(context).edit()
            .putString(KEY_TOKEN, token)
            .putString(KEY_USER, username)
            .putLong(KEY_LOGIN_TS, now)
            .apply()
    }

    fun getToken(context: Context): String? =
        prefs(context).getString(KEY_TOKEN, null)

    fun getUsername(context: Context): String? =
        prefs(context).getString(KEY_USER, null)

    fun getLoginTimestamp(context: Context): Long =
        prefs(context).getLong(KEY_LOGIN_TS, 0L)

    fun clear(context: Context) {
        prefs(context).edit().clear().apply()
    }

    fun hasToken(context: Context): Boolean = !getToken(context).isNullOrBlank()

    fun ensureLegacyLoginTimestamp(context: Context) {
        if (!hasToken(context)) return
        if (getLoginTimestamp(context) != 0L) return
        val now = System.currentTimeMillis()
        prefs(context).edit().putLong(KEY_LOGIN_TS, now).apply()
        Log.d(TAG, "Set login_ts for session without timestamp")
    }

    fun isSessionValid(context: Context): Boolean {
        ensureLegacyLoginTimestamp(context)
        val token = getToken(context)
        if (token.isNullOrBlank()) return false
        val ts = getLoginTimestamp(context)
        if (ts <= 0L) return false
        return System.currentTimeMillis() - ts < SESSION_TTL_MS
    }

    fun isAuthError(throwable: Throwable): Boolean {
        val msg = throwable.message.orEmpty()
        if (throwable is ApiException) {
            val code = throwable.code.orEmpty()
            if (code == "UNAUTHORIZED"
                || code == "FORBIDDEN"
                || code == "PASSWORD_CHANGE_REQUIRED"
            ) {
                return true
            }
        }
        return msg.contains("401", ignoreCase = true)
            || msg.contains("403", ignoreCase = true)
            || msg.contains("Invalid or expired token", ignoreCase = true)
            || msg.contains("Missing Bearer token", ignoreCase = true)
            || msg.contains("Insufficient permissions", ignoreCase = true)
            || msg.contains("Password change required", ignoreCase = true)
    }
}
