package com.nexus.cross.sdk.unity

import android.content.Context
import android.content.SharedPreferences
import android.security.keystore.KeyGenParameterSpec
import android.security.keystore.KeyProperties
import android.util.Base64
import android.util.Log
import com.unity3d.player.UnityPlayer
import java.nio.charset.StandardCharsets
import java.security.KeyStore
import javax.crypto.Cipher
import javax.crypto.KeyGenerator
import javax.crypto.SecretKey
import javax.crypto.spec.GCMParameterSpec

/**
 * Secure storage based on Android Keystore + AES/GCM.
 * Uses only platform APIs with no additional Gradle dependencies.
 */
class CROSSxSecureStorage private constructor() {
    companion object {
        private const val TAG = "CROSSxSecureStorage"
        private const val KEYSTORE_ALIAS = "crossx_sdk_key"
        private const val PREFS_NAME = "crossx_sdk_secure"
        private const val TRANSFORMATION = "AES/GCM/NoPadding"
        private const val GCM_IV_LENGTH = 12
        private const val GCM_TAG_BITS = 128

        private fun getOrCreateKey(): SecretKey {
            val ks = KeyStore.getInstance("AndroidKeyStore").apply { load(null) }

            if (ks.containsAlias(KEYSTORE_ALIAS)) {
                return ks.getKey(KEYSTORE_ALIAS, null) as SecretKey
            }

            val gen = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore")
            gen.init(
                KeyGenParameterSpec.Builder(
                    KEYSTORE_ALIAS,
                    KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
                )
                    .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
                    .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
                    .build()
            )
            return gen.generateKey()
        }

        private fun getPrefs(): SharedPreferences {
            val ctx = UnityPlayer.currentActivity.applicationContext
            return ctx.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
        }

        @JvmStatic
        fun save(key: String, value: String) {
            try {
                val secretKey = getOrCreateKey()
                val cipher = Cipher.getInstance(TRANSFORMATION).apply {
                    init(Cipher.ENCRYPT_MODE, secretKey)
                }

                val iv = cipher.iv
                val encrypted = cipher.doFinal(value.toByteArray(StandardCharsets.UTF_8))

                val combined = ByteArray(iv.size + encrypted.size)
                System.arraycopy(iv, 0, combined, 0, iv.size)
                System.arraycopy(encrypted, 0, combined, iv.size, encrypted.size)

                getPrefs().edit()
                    .putString(key, Base64.encodeToString(combined, Base64.NO_WRAP))
                    .apply()
            } catch (e: Exception) {
                Log.e(TAG, "Save failed for key '$key': ${e.message}")
            }
        }

        @JvmStatic
        fun load(key: String): String? {
            return try {
                val b64 = getPrefs().getString(key, null) ?: return null
                val combined = Base64.decode(b64, Base64.NO_WRAP)
                if (combined.size <= GCM_IV_LENGTH) return null

                val iv = combined.copyOfRange(0, GCM_IV_LENGTH)
                val encrypted = combined.copyOfRange(GCM_IV_LENGTH, combined.size)

                val secretKey = getOrCreateKey()
                val cipher = Cipher.getInstance(TRANSFORMATION).apply {
                    init(Cipher.DECRYPT_MODE, secretKey, GCMParameterSpec(GCM_TAG_BITS, iv))
                }

                String(cipher.doFinal(encrypted), StandardCharsets.UTF_8)
            } catch (e: Exception) {
                Log.e(TAG, "Load failed for key '$key': ${e.message}")
                null
            }
        }

        @JvmStatic
        fun delete(key: String) {
            getPrefs().edit().remove(key).apply()
        }

        @JvmStatic
        fun has(key: String): Boolean {
            return getPrefs().contains(key)
        }
    }
}
