/*
 * SPDX-License-Identifier: GPL-3.0-or-later
 */
package com.runicgateway.app.core.auth

import android.content.Context
import android.content.SharedPreferences
import androidx.security.crypto.EncryptedSharedPreferences
import androidx.security.crypto.MasterKey
import dagger.hilt.android.qualifiers.ApplicationContext
import javax.inject.Inject
import javax.inject.Singleton

/**
 * [TrustTokenStore] backed by its **own** EncryptedSharedPreferences file
 * (Tink/AES-256-GCM), distinct from the session store so it is never wiped by
 * [SessionManager.onSignedOut] — the trust token must outlive a logout to do its
 * job (TRUSTED_DEVICES_MFA.md). The token is stored alongside the username it was
 * minted for so [tokenFor] only returns it for a matching login.
 *
 * The prefs handle is lazy so a device that never trusts pays the keystore cost
 * only if a token is actually stored or read.
 */
@Singleton
class EncryptedTrustTokenStore @Inject constructor(
    @param:ApplicationContext private val context: Context,
) : TrustTokenStore {

    private val prefs: SharedPreferences by lazy {
        val masterKey = MasterKey.Builder(context)
            .setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
            .build()
        EncryptedSharedPreferences.create(
            context,
            PREFS_NAME,
            masterKey,
            EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
            EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM,
        )
    }

    override fun tokenFor(username: String): String? {
        val token = prefs.getString(KEY_TOKEN, null) ?: return null
        val owner = prefs.getString(KEY_USERNAME, null) ?: return null
        // Case-insensitive: usernames are matched case-insensitively server-side.
        return if (owner.equals(username, ignoreCase = true)) token else null
    }

    override fun save(username: String, token: String) {
        prefs.edit()
            .putString(KEY_TOKEN, token)
            .putString(KEY_USERNAME, username)
            .apply()
    }

    override fun clear() {
        prefs.edit().clear().apply()
    }

    private companion object {
        const val PREFS_NAME = "runic_trust"
        const val KEY_TOKEN = "trust_token"
        const val KEY_USERNAME = "trust_username"
    }
}
