package com.korancrew.brizzi.hce

import android.content.Context
import android.content.SharedPreferences
import androidx.security.crypto.EncryptedSharedPreferences
import androidx.security.crypto.MasterKey
import org.json.JSONArray
import org.json.JSONObject

/**
 * Persistensi data kartu di SharedPreferences terenkripsi.
 *
 * Data JSON disimpan di:
 * - Nama prefs: brizzi_hce_secure
 * - Kunci utama: card_json
 *
 * Kunci dan value dienkripsi menggunakan Android Keystore MasterKey.
 */
class BrizziSecureStorage(context: Context) {
    private val appContext = context.applicationContext
    private val prefs: SharedPreferences? by lazy {
        runCatching {
            val masterKey = MasterKey.Builder(appContext, MasterKey.DEFAULT_MASTER_KEY_ALIAS)
                .setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
                .build()
            EncryptedSharedPreferences.create(
                appContext,
                PREF_NAME,
                masterKey,
                EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
                EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM,
            )
        }.getOrNull()
    }

    /** Ambil data card dari storage. Jika rusak/tidak ada, return null. */
    fun loadCard(): BrizziCard? {
        val raw = prefs?.getString(KEY_CARD_JSON, null) ?: return null
        return runCatching {
            val json = JSONObject(raw)
            BrizziCard(
                cardNumberHex = json.getString(KEY_CARD_NUMBER),
                persoDateHex = json.getString(KEY_PERSO_DATE),
                issuerCodeHex = json.getString(KEY_ISSUER),
                cardStatusHex = json.getString(KEY_CARD_STATUS),
                uidHex = json.getString(KEY_UID),
                keyCard00Hex = json.getString(KEY_KEY_CARD_00),
                keyCard01Hex = json.getString(KEY_KEY_CARD_01),
                randomNumberHex = json.getString(KEY_RANDOM),
                lastTransactionDateHex = json.getString(KEY_LAST_TXN_DATE),
                akumDebetHex = json.getString(KEY_AKUM_DEBET),
                balance = json.getInt(KEY_BALANCE),
                logs = parseLogs(json.getJSONArray(KEY_LOGS)),
            )
        }.getOrNull()
    }

    /**
     * Simpan snapshot card.
     * Hanya field yang didefinisikan di [BrizziCard] yang diserialisasi ke JSON.
     */
    fun saveCard(card: BrizziCard) {
        val json = JSONObject().apply {
            put(KEY_CARD_NUMBER, card.cardNumberHex)
            put(KEY_PERSO_DATE, card.persoDateHex)
            put(KEY_ISSUER, card.issuerCodeHex)
            put(KEY_CARD_STATUS, card.cardStatusHex)
            put(KEY_UID, card.uidHex)
            put(KEY_KEY_CARD_00, card.keyCard00Hex)
            put(KEY_KEY_CARD_01, card.keyCard01Hex)
            put(KEY_RANDOM, card.randomNumberHex)
            put(KEY_LAST_TXN_DATE, card.lastTransactionDateHex)
            put(KEY_AKUM_DEBET, card.akumDebetHex)
            put(KEY_BALANCE, card.balance)
            put(
                KEY_LOGS,
                JSONArray().apply {
                    card.logs.take(MAX_LOGS).forEach { log ->
                        put(
                            JSONObject().apply {
                                put(KEY_LOG_MERCHANT, log.merchantIdHex)
                                put(KEY_LOG_TERMINAL, log.terminalIdAsciiHex)
                                put(KEY_LOG_DATE, log.trxDateHex)
                                put(KEY_LOG_TIME, log.trxTimeHex)
                                put(KEY_LOG_TYPE, log.trxTypeHex)
                                put(KEY_LOG_AMOUNT, log.amountReversedHex)
                                put(KEY_LOG_BAL_BEFORE, log.balanceBeforeReversedHex)
                                put(KEY_LOG_BAL_AFTER, log.balanceAfterReversedHex)
                            },
                        )
                    }
                },
            )
        }
        prefs?.edit()
            ?.putString(KEY_CARD_JSON, json.toString())
            ?.apply()
    }

    /** Hapus data card tersimpan. */
    fun clear() {
        prefs?.edit()?.remove(KEY_CARD_JSON)?.apply()
    }

    /** Parse list log dari JSONArray dengan default fallback value agar resilient. */
    private fun parseLogs(jsonArray: JSONArray): List<BrizziLogRecord> {
        val result = mutableListOf<BrizziLogRecord>()
        for (index in 0 until jsonArray.length()) {
            val raw = jsonArray.optJSONObject(index) ?: continue
            val merchant = raw.optString(KEY_LOG_MERCHANT, "0000000000000000")
            val terminal = raw.optString(KEY_LOG_TERMINAL, "0000000000000000")
            val date = raw.optString(KEY_LOG_DATE, "000000")
            val time = raw.optString(KEY_LOG_TIME, "000000")
            val type = raw.optString(KEY_LOG_TYPE, "00")
            val amount = raw.optString(KEY_LOG_AMOUNT, "000000")
            val before = raw.optString(KEY_LOG_BAL_BEFORE, "000000")
            val after = raw.optString(KEY_LOG_BAL_AFTER, "000000")
            result.add(
                BrizziLogRecord(
                    merchantIdHex = merchant,
                    terminalIdAsciiHex = terminal,
                    trxDateHex = date,
                    trxTimeHex = time,
                    trxTypeHex = type,
                    amountReversedHex = amount,
                    balanceBeforeReversedHex = before,
                    balanceAfterReversedHex = after,
                ),
            )
        }
        return result
    }

    companion object {
        private const val PREF_NAME = "brizzi_hce_secure"
        private const val KEY_CARD_JSON = "card_json"
        private const val KEY_CARD_NUMBER = "cardNumberHex"
        private const val KEY_PERSO_DATE = "persoDateHex"
        private const val KEY_ISSUER = "issuerCodeHex"
        private const val KEY_CARD_STATUS = "cardStatusHex"
        private const val KEY_UID = "uidHex"
        private const val KEY_KEY_CARD_00 = "keyCard00Hex"
        private const val KEY_KEY_CARD_01 = "keyCard01Hex"
        private const val KEY_RANDOM = "randomNumberHex"
        private const val KEY_LAST_TXN_DATE = "lastTransactionDateHex"
        private const val KEY_AKUM_DEBET = "akumDebetHex"
        private const val KEY_BALANCE = "balance"
        private const val KEY_LOGS = "logs"
        private const val KEY_LOG_MERCHANT = "merchantIdHex"
        private const val KEY_LOG_TERMINAL = "terminalIdAsciiHex"
        private const val KEY_LOG_DATE = "trxDateHex"
        private const val KEY_LOG_TIME = "trxTimeHex"
        private const val KEY_LOG_TYPE = "trxTypeHex"
        private const val KEY_LOG_AMOUNT = "amountReversedHex"
        private const val KEY_LOG_BAL_BEFORE = "balanceBeforeReversedHex"
        private const val KEY_LOG_BAL_AFTER = "balanceAfterReversedHex"
        private const val MAX_LOGS = 12
    }
}
