package com.seven.ikar.kotlin.core.settings

import android.content.Context
import android.util.Base64
import com.seven.ikar.kotlin.core.model.PrivacySettingsDto
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import java.security.MessageDigest
import java.security.SecureRandom
import javax.crypto.SecretKeyFactory
import javax.crypto.spec.PBEKeySpec

data class PrivacyRuntimeSnapshot(
    val passcodeLockEnabled: Boolean = false,
    val showMessagePreview: Boolean = true
)

class AndroidPrivacyRuntimeSettings(context: Context) {
    private val preferences = context.getSharedPreferences(PREFERENCES_NAME, Context.MODE_PRIVATE)
    private val _snapshot = MutableStateFlow(loadSnapshot())
    val snapshot: StateFlow<PrivacyRuntimeSnapshot> = _snapshot.asStateFlow()

    fun loadSnapshot(): PrivacyRuntimeSnapshot =
        PrivacyRuntimeSnapshot(
            passcodeLockEnabled = preferences.getBoolean(KEY_PASSCODE_LOCK_ENABLED, false),
            showMessagePreview = preferences.getBoolean(KEY_SHOW_MESSAGE_PREVIEW, true)
        )

    fun saveFrom(settings: PrivacySettingsDto) {
        if (!settings.passcodeLockEnabled) {
            clearPasscode()
        }
        saveSnapshot(
            PrivacyRuntimeSnapshot(
                passcodeLockEnabled = settings.passcodeLockEnabled,
                showMessagePreview = settings.showMessagePreview
            )
        )
    }

    fun hasPasscode(): Boolean =
        !preferences.getString(KEY_PASSCODE_SALT, null).isNullOrBlank() &&
            !preferences.getString(KEY_PASSCODE_HASH, null).isNullOrBlank()

    fun setPasscode(passcode: String) {
        val salt = ByteArray(PasscodeSaltBytes)
        SecureRandom().nextBytes(salt)
        val hash = hashPasscode(passcode, salt)
        preferences.edit()
            .putString(KEY_PASSCODE_SALT, Base64.encodeToString(salt, Base64.NO_WRAP))
            .putString(KEY_PASSCODE_HASH, Base64.encodeToString(hash, Base64.NO_WRAP))
            .apply()
    }

    fun verifyPasscode(passcode: String): Boolean {
        val salt = preferences.getString(KEY_PASSCODE_SALT, null)
            ?.let { Base64.decode(it, Base64.NO_WRAP) }
            ?: return false
        val expectedHash = preferences.getString(KEY_PASSCODE_HASH, null)
            ?.let { Base64.decode(it, Base64.NO_WRAP) }
            ?: return false
        val actualHash = hashPasscode(passcode, salt)
        return MessageDigest.isEqual(expectedHash, actualHash)
    }

    fun clearPasscode() {
        preferences.edit()
            .remove(KEY_PASSCODE_SALT)
            .remove(KEY_PASSCODE_HASH)
            .apply()
    }

    private fun saveSnapshot(snapshot: PrivacyRuntimeSnapshot) {
        preferences.edit()
            .putBoolean(KEY_PASSCODE_LOCK_ENABLED, snapshot.passcodeLockEnabled)
            .putBoolean(KEY_SHOW_MESSAGE_PREVIEW, snapshot.showMessagePreview)
            .apply()
        _snapshot.value = snapshot
    }

    private fun hashPasscode(passcode: String, salt: ByteArray): ByteArray {
        val spec = PBEKeySpec(passcode.toCharArray(), salt, PasscodeIterations, PasscodeKeyBits)
        return SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1")
            .generateSecret(spec)
            .encoded
    }

    companion object {
        private const val PREFERENCES_NAME = "ikar_kotlin_privacy_runtime"
        private const val KEY_PASSCODE_LOCK_ENABLED = "passcode_lock_enabled"
        private const val KEY_SHOW_MESSAGE_PREVIEW = "show_message_preview"
        private const val KEY_PASSCODE_SALT = "passcode_salt"
        private const val KEY_PASSCODE_HASH = "passcode_hash"
        private const val PasscodeSaltBytes = 16
        private const val PasscodeIterations = 120_000
        private const val PasscodeKeyBits = 256
    }
}

class AppLockState {
    private val _isLocked = MutableStateFlow(false)
    val isLocked: StateFlow<Boolean> = _isLocked.asStateFlow()

    fun setLocked(locked: Boolean) {
        _isLocked.value = locked
    }
}
