package com.rosetta.messenger.biometric

import android.content.Context
import android.content.pm.PackageManager
import android.os.Build
import android.security.keystore.KeyGenParameterSpec
import android.security.keystore.KeyPermanentlyInvalidatedException
import android.security.keystore.KeyProperties
import android.util.Base64
import android.util.Log
import androidx.biometric.BiometricManager
import androidx.biometric.BiometricPrompt
import androidx.core.content.ContextCompat
import androidx.fragment.app.FragmentActivity
import java.security.KeyStore
import java.security.cert.Certificate
import java.util.Arrays
import javax.crypto.Cipher
import javax.crypto.KeyGenerator
import javax.crypto.SecretKey
import javax.crypto.spec.GCMParameterSpec

/**
 * Безопасный менеджер биометрической аутентификации
 * 
 * Использует Android Keystore для хранения ключей шифрования:
 * - Ключи генерируются и хранятся в аппаратном модуле безопасности (TEE/StrongBox)
 * - Ключи привязаны к биометрии через setUserAuthenticationRequired
 * - Ключи инвалидируются при изменении биометрических данных
 * - Используется AES-GCM для аутентифицированного шифрования
 * - CryptoObject привязывает криптографические операции к биометрии
 */
class BiometricAuthManager(private val context: Context) {
    
    companion object {
        private const val TAG = "BiometricAuthManager"
        private const val KEYSTORE_PROVIDER = "AndroidKeyStore"
        private const val KEY_ALIAS = "rosetta_biometric_key"
        private const val TRANSFORMATION = "AES/GCM/NoPadding"
        private const val GCM_TAG_LENGTH = 128
        private const val IV_SEPARATOR = "|"
        
        // Google Hardware Attestation Root Certificate
        private const val GOOGLE_ROOT_CA_FINGERPRINT = 
            "98:BD:5B:98:E9:D3:29:F4:CF:10:45:76:A5:00:7D:A8:08:7A:70:50:4D:FF:4D:C5:95:3A:7F:C3:73:79:0F:ED"
    }
    
    private val keyStore: KeyStore = KeyStore.getInstance(KEYSTORE_PROVIDER).apply {
        load(null)
    }

    /**
     * Проверяет доступность STRONG биометрической аутентификации
     * BIOMETRIC_STRONG требует Class 3 биометрию (отпечаток/лицо с криптографической привязкой)
     */
    fun isFingerprintHardwareAvailable(): Boolean {
        return context.packageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)
    }

    fun isBiometricAvailable(): BiometricAvailability {
        if (!isFingerprintHardwareAvailable()) {
            return BiometricAvailability.NotAvailable("Отпечаток пальца не поддерживается")
        }

        val biometricManager = BiometricManager.from(context)
        
        return when (biometricManager.canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_STRONG)) {
            BiometricManager.BIOMETRIC_SUCCESS -> 
                BiometricAvailability.Available
            
            BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE ->
                BiometricAvailability.NotAvailable("Биометрическое оборудование недоступно")
            
            BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE ->
                BiometricAvailability.NotAvailable("Биометрическое оборудование временно недоступно")
            
            BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED ->
                BiometricAvailability.NotEnrolled("Биометрические данные не настроены")
            
            BiometricManager.BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED ->
                BiometricAvailability.NotAvailable("Требуется обновление безопасности")
            
            BiometricManager.BIOMETRIC_ERROR_UNSUPPORTED ->
                BiometricAvailability.NotAvailable("Биометрическая аутентификация не поддерживается")
            
            BiometricManager.BIOMETRIC_STATUS_UNKNOWN ->
                BiometricAvailability.NotAvailable("Неизвестный статус")
            
            else -> BiometricAvailability.NotAvailable("Неизвестная ошибка")
        }
    }

    /**
     * Шифрует пароль с использованием ключа из Android Keystore
     * Шифрование привязано к биометрии через CryptoObject
     */
    fun encryptPassword(
        activity: FragmentActivity,
        password: String,
        onSuccess: (String) -> Unit,
        onError: (String) -> Unit,
        onCancel: () -> Unit
    ) {
        try {
            // Генерируем или получаем ключ
            val secretKey = getOrCreateSecretKey()
            
            // Создаем Cipher для шифрования
            val cipher = Cipher.getInstance(TRANSFORMATION)
            cipher.init(Cipher.ENCRYPT_MODE, secretKey)
            
            // Показываем биометрический промпт с CryptoObject
            showBiometricPromptWithCrypto(
                activity = activity,
                cipher = cipher,
                title = "Сохранить пароль",
                subtitle = "Подтвердите биометрией для защиты пароля",
                onSuccess = { authenticatedCipher ->
                    try {
                        val passwordBytes = password.toByteArray(Charsets.UTF_8)
                        try {
                            val encrypted = authenticatedCipher.doFinal(passwordBytes)
                            val iv = authenticatedCipher.iv
                            
                            // Сохраняем IV и зашифрованные данные
                            val ivString = Base64.encodeToString(iv, Base64.NO_WRAP)
                            val encryptedString = Base64.encodeToString(encrypted, Base64.NO_WRAP)
                            
                            onSuccess("$ivString$IV_SEPARATOR$encryptedString")
                        } finally {
                            // Secure memory wipe - обнуляем пароль в памяти
                            Arrays.fill(passwordBytes, 0.toByte())
                        }
                    } catch (e: Exception) {
                        onError("Ошибка шифрования: ${e.message}")
                    }
                },
                onError = onError,
                onCancel = onCancel
            )
        } catch (e: KeyPermanentlyInvalidatedException) {
            removeBiometricData()
            onError("Биометрические данные изменились. Пожалуйста, настройте заново.")
        } catch (e: Exception) {
            onError("Ошибка инициализации: ${formatInitializationError(e)}")
        }
    }

    /**
     * Расшифровывает пароль с использованием ключа из Android Keystore
     * Расшифровка возможна только после успешной биометрической аутентификации
     */
    fun decryptPassword(
        activity: FragmentActivity,
        encryptedData: String,
        onSuccess: (String) -> Unit,
        onError: (String) -> Unit,
        onCancel: () -> Unit
    ) {
        try {
            val parts = encryptedData.split(IV_SEPARATOR)
            if (parts.size != 2) {
                onError("Неверный формат зашифрованных данных")
                return
            }
            
            val iv = Base64.decode(parts[0], Base64.NO_WRAP)
            val encrypted = Base64.decode(parts[1], Base64.NO_WRAP)
            
            // Получаем ключ из Keystore
            val secretKey = getSecretKey()
            if (secretKey == null) {
                onError("Ключ не найден. Пожалуйста, настройте биометрию заново.")
                return
            }
            
            // Создаем Cipher для расшифровки с тем же IV
            val cipher = Cipher.getInstance(TRANSFORMATION)
            val spec = GCMParameterSpec(GCM_TAG_LENGTH, iv)
            cipher.init(Cipher.DECRYPT_MODE, secretKey, spec)
            
            // Показываем биометрический промпт с CryptoObject
            showBiometricPromptWithCrypto(
                activity = activity,
                cipher = cipher,
                title = "Разблокировать",
                subtitle = "Подтвердите биометрией для входа",
                onSuccess = { authenticatedCipher ->
                    var decrypted: ByteArray? = null
                    try {
                        decrypted = authenticatedCipher.doFinal(encrypted)
                        onSuccess(String(decrypted, Charsets.UTF_8))
                    } catch (e: Exception) {
                        onError("Ошибка расшифровки: ${e.message}")
                    } finally {
                        // Secure memory wipe - обнуляем расшифрованные данные
                        decrypted?.let { Arrays.fill(it, 0.toByte()) }
                    }
                },
                onError = onError,
                onCancel = onCancel
            )
        } catch (e: KeyPermanentlyInvalidatedException) {
            removeBiometricData()
            onError("Биометрические данные изменились. Пожалуйста, войдите с паролем и настройте биометрию заново.")
        } catch (e: Exception) {
            onError("Ошибка инициализации: ${formatInitializationError(e)}")
        }
    }

    /**
     * Показывает биометрический промпт с криптографической привязкой (CryptoObject)
     */
    private fun showBiometricPromptWithCrypto(
        activity: FragmentActivity,
        cipher: Cipher,
        title: String,
        subtitle: String,
        onSuccess: (Cipher) -> Unit,
        onError: (String) -> Unit,
        onCancel: () -> Unit
    ) {
        val executor = ContextCompat.getMainExecutor(context)
        
        val callback = object : BiometricPrompt.AuthenticationCallback() {
            override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
                super.onAuthenticationError(errorCode, errString)
                when (errorCode) {
                    BiometricPrompt.ERROR_USER_CANCELED,
                    BiometricPrompt.ERROR_NEGATIVE_BUTTON,
                    BiometricPrompt.ERROR_CANCELED -> onCancel()
                    BiometricPrompt.ERROR_LOCKOUT,
                    BiometricPrompt.ERROR_LOCKOUT_PERMANENT -> 
                        onError("Слишком много попыток. Попробуйте позже.")
                    else -> onError(errString.toString())
                }
            }

            override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
                super.onAuthenticationSucceeded(result)
                // Получаем аутентифицированный Cipher из CryptoObject
                val authenticatedCipher = result.cryptoObject?.cipher
                if (authenticatedCipher != null) {
                    onSuccess(authenticatedCipher)
                } else {
                    onError("Ошибка: криптографический объект не получен")
                }
            }

            override fun onAuthenticationFailed() {
                super.onAuthenticationFailed()
// Не вызываем onError - пользователь может попробовать снова
            }
        }

        val biometricPrompt = BiometricPrompt(activity, executor, callback)

        val promptInfo = BiometricPrompt.PromptInfo.Builder()
            .setTitle(title)
            .setSubtitle(subtitle)
            .setNegativeButtonText("Отмена")
            .setAllowedAuthenticators(BiometricManager.Authenticators.BIOMETRIC_STRONG)
            .setConfirmationRequired(false)
            .build()

        // Аутентификация с CryptoObject - криптографическая операция привязана к биометрии
        biometricPrompt.authenticate(promptInfo, BiometricPrompt.CryptoObject(cipher))
    }

    /**
     * Генерирует новый ключ или возвращает существующий из Android Keystore
     */
    private fun getOrCreateSecretKey(): SecretKey {
        // Проверяем, есть ли уже ключ
        getSecretKey()?.let { return it }

        val attempts = buildKeyGenerationAttempts()
        var lastError: Exception? = null

        for ((index, config) in attempts.withIndex()) {
            try {
                val keyGenerator = KeyGenerator.getInstance(
                    KeyProperties.KEY_ALGORITHM_AES,
                    KEYSTORE_PROVIDER
                )
                val spec = buildKeyGenSpec(config)
                keyGenerator.init(spec)
                return keyGenerator.generateKey()
            } catch (e: Exception) {
                lastError = e
                Log.w(
                    TAG,
                    "Key generation attempt ${index + 1}/${attempts.size} failed " +
                        "(strongBox=${config.useStrongBox}, attestation=${config.useAttestation}, " +
                        "unlockedRequired=${config.requireUnlockedDevice})",
                    e
                )
                removeKeyAliasSilently()
            }
        }

        throw IllegalStateException("Failed to generate key", lastError)
    }

    private fun buildKeyGenerationAttempts(): List<KeyGenerationConfig> {
        val attempts = mutableListOf<KeyGenerationConfig>()

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            attempts += KeyGenerationConfig(
                useStrongBox = true,
                useAttestation = true,
                requireUnlockedDevice = true
            )
        }

        attempts += KeyGenerationConfig(
            useStrongBox = false,
            useAttestation = true,
            requireUnlockedDevice = true
        )

        attempts += KeyGenerationConfig(
            useStrongBox = false,
            useAttestation = false,
            requireUnlockedDevice = true
        )

        attempts += KeyGenerationConfig(
            useStrongBox = false,
            useAttestation = false,
            requireUnlockedDevice = false
        )

        return attempts
    }

    private fun buildKeyGenSpec(config: KeyGenerationConfig): KeyGenParameterSpec {
        val builder = KeyGenParameterSpec.Builder(
            KEY_ALIAS,
            KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
        )
            .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
            .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
            .setKeySize(256)
            .setUserAuthenticationRequired(true)
            .setInvalidatedByBiometricEnrollment(true)

        if (config.requireUnlockedDevice && Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            builder.setUnlockedDeviceRequired(true)
        }

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            builder.setUserAuthenticationParameters(
                0,
                KeyProperties.AUTH_BIOMETRIC_STRONG
            )
        }

        if (config.useAttestation && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            builder.setAttestationChallenge(generateAttestationChallenge())
        }

        if (config.useStrongBox && Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            builder.setIsStrongBoxBacked(true)
        }

        return builder.build()
    }

    private fun removeKeyAliasSilently() {
        try {
            if (keyStore.containsAlias(KEY_ALIAS)) {
                keyStore.deleteEntry(KEY_ALIAS)
            }
        } catch (_: Exception) {
        }
    }

    private fun formatInitializationError(error: Throwable): String {
        val rootCause = generateSequence(error) { it.cause }.lastOrNull() ?: error
        val message = rootCause.message ?: error.message ?: "Unknown error"

        return if (message.contains("Failed to generate key", ignoreCase = true)) {
            "Не удалось создать ключ. Проверьте, что на устройстве включена блокировка экрана и настроена биометрия."
        } else {
            message
        }
    }

    /**
     * Получает существующий ключ из Keystore
     */
    private fun getSecretKey(): SecretKey? {
        return try {
            keyStore.getKey(KEY_ALIAS, null) as? SecretKey
        } catch (e: Exception) {
            null
        }
    }

    /**
     * Удаляет ключ из Android Keystore
     * Это делает все ранее зашифрованные данные недоступными
     */
    fun removeBiometricData() {
        try {
            if (keyStore.containsAlias(KEY_ALIAS)) {
                keyStore.deleteEntry(KEY_ALIAS)
            }
        } catch (e: Exception) {
        }
    }
    
    /**
     * Проверяет, есть ли сохраненный ключ
     */
    fun hasStoredKey(): Boolean {
        return try {
            keyStore.containsAlias(KEY_ALIAS)
        } catch (e: Exception) {
            false
        }
    }
    
    /**
     * Генерирует случайный challenge для Key Attestation
     */
    private fun generateAttestationChallenge(): ByteArray {
        val challenge = ByteArray(32)
        java.security.SecureRandom().nextBytes(challenge)
        return challenge
    }
    
    /**
     * Проверяет Key Attestation - убеждается что ключ реально в TEE/StrongBox
     * Возвращает true если attestation валидный или недоступен (fallback)
     */
    fun verifyKeyAttestation(): KeyAttestationResult {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
            return KeyAttestationResult.NotSupported
        }
        
        return try {
            val certificateChain = keyStore.getCertificateChain(KEY_ALIAS)
            if (certificateChain.isNullOrEmpty()) {
                return KeyAttestationResult.NotSupported
            }
            
            // Проверяем что цепочка валидна
            for (i in 0 until certificateChain.size - 1) {
                try {
                    certificateChain[i].verify(certificateChain[i + 1].publicKey)
                } catch (e: Exception) {
                    return KeyAttestationResult.Invalid("Цепочка сертификатов недействительна")
                }
            }
            
            // Проверяем attestation extension в leaf сертификате
            val leafCert = certificateChain[0] as? java.security.cert.X509Certificate
            if (leafCert != null) {
                val attestationExtension = leafCert.getExtensionValue("1.3.6.1.4.1.11129.2.1.17")
                if (attestationExtension != null) {
                    return KeyAttestationResult.Valid(isStrongBox = isKeyInStrongBox())
                }
            }
            
            KeyAttestationResult.NotSupported
        } catch (e: Exception) {
            KeyAttestationResult.Invalid(e.message ?: "Unknown error")
        }
    }
    
    /**
     * Проверяет находится ли ключ в StrongBox
     */
    private fun isKeyInStrongBox(): Boolean {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) return false
        
        return try {
            val key = keyStore.getKey(KEY_ALIAS, null)
            val keyInfo = java.security.KeyFactory.getInstance(
                key.algorithm, KEYSTORE_PROVIDER
            ).getKeySpec(key, android.security.keystore.KeyInfo::class.java)
            
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
                keyInfo.securityLevel == KeyProperties.SECURITY_LEVEL_STRONGBOX
            } else {
                @Suppress("DEPRECATION")
                keyInfo.isInsideSecureHardware
            }
        } catch (e: Exception) {
            false
        }
    }
    
    /**
     * Проверяет целостность устройства (root detection)
     */
    fun checkDeviceIntegrity(): DeviceIntegrityResult {
        val issues = mutableListOf<String>()
        
        // Проверка на root
        val rootIndicators = listOf(
            "/system/app/Superuser.apk",
            "/sbin/su",
            "/system/bin/su",
            "/system/xbin/su",
            "/data/local/xbin/su",
            "/data/local/bin/su",
            "/system/sd/xbin/su",
            "/system/bin/failsafe/su",
            "/data/local/su",
            "/su/bin/su",
            "/system/xbin/daemonsu",
            "/system/bin/.ext/.su",
            "/system/etc/init.d/99SuperSUDaemon",
            "/dev/com.koushikdutta.superuser.daemon/",
            "/system/app/Superuser",
            "/system/app/SuperSU",
            "/system/app/Magisk"
        )
        
        for (path in rootIndicators) {
            if (java.io.File(path).exists()) {
                issues.add("Root indicator found: $path")
                break
            }
        }
        
        // Проверка Build tags
        val buildTags = Build.TAGS
        if (buildTags != null && buildTags.contains("test-keys")) {
            issues.add("Device has test-keys")
        }
        
        // Проверка dangerous props
        try {
            val process = Runtime.getRuntime().exec(arrayOf("/system/bin/getprop", "ro.debuggable"))
            val reader = java.io.BufferedReader(java.io.InputStreamReader(process.inputStream))
            val debuggable = reader.readLine()
            reader.close()
            if (debuggable == "1") {
                issues.add("Device is debuggable")
            }
        } catch (e: Exception) {
            // Ignore
        }
        
        return if (issues.isEmpty()) {
            DeviceIntegrityResult.Secure
        } else {
            DeviceIntegrityResult.Compromised(issues)
        }
    }
}

private data class KeyGenerationConfig(
    val useStrongBox: Boolean,
    val useAttestation: Boolean,
    val requireUnlockedDevice: Boolean
)

/**
 * Результат проверки Key Attestation
 */
sealed class KeyAttestationResult {
    data class Valid(val isStrongBox: Boolean) : KeyAttestationResult()
    data class Invalid(val reason: String) : KeyAttestationResult()
    object NotSupported : KeyAttestationResult()
}

/**
 * Результат проверки целостности устройства
 */
sealed class DeviceIntegrityResult {
    object Secure : DeviceIntegrityResult()
    data class Compromised(val issues: List<String>) : DeviceIntegrityResult()
}

/**
 * Результат проверки доступности биометрии
 */
sealed class BiometricAvailability {
    object Available : BiometricAvailability()
    data class NotAvailable(val reason: String) : BiometricAvailability()
    data class NotEnrolled(val reason: String) : BiometricAvailability()
}
