package com.inou.clawdnode.security

import android.content.Context
import android.security.keystore.KeyGenParameterSpec
import android.security.keystore.KeyProperties
import android.util.Base64
import android.util.Log
import java.security.*
import java.security.spec.ECGenParameterSpec

/**
 * Manages device identity using Android Keystore.
 * 
 * Generates and stores an EC P-256 keypair for signing Gateway challenge nonces.
 * The private key never leaves the secure hardware (TEE/SE) on supported devices.
 */
class DeviceIdentity(context: Context) {
    
    private val tag = "DeviceIdentity"
    private val keyAlias = "clawdnode_device_key"
    
    private val keyStore: KeyStore by lazy {
        KeyStore.getInstance("AndroidKeyStore").apply { load(null) }
    }
    
    /**
     * Get or generate the device's public key
     */
    val publicKey: String by lazy {
        ensureKeyPair()
        val publicKey = keyStore.getCertificate(keyAlias)?.publicKey
            ?: throw IllegalStateException("No public key available")
        Base64.encodeToString(publicKey.encoded, Base64.NO_WRAP)
    }
    
    /**
     * Get device ID (fingerprint of the public key)
     */
    val deviceId: String by lazy {
        ensureKeyPair()
        val publicKey = keyStore.getCertificate(keyAlias)?.publicKey
            ?: throw IllegalStateException("No public key available")
        
        // Create fingerprint using SHA-256 of the public key
        val digest = MessageDigest.getInstance("SHA-256")
        val hash = digest.digest(publicKey.encoded)
        
        // Return as hex string (first 16 bytes = 32 chars)
        hash.take(16).joinToString("") { "%02x".format(it) }
    }
    
    /**
     * Sign a challenge nonce for gateway authentication
     * 
     * @param nonce The challenge nonce from the gateway
     * @return Signature and timestamp
     */
    fun signChallenge(nonce: String): SignedChallenge {
        ensureKeyPair()
        
        val signedAt = System.currentTimeMillis()
        val dataToSign = "$nonce:$signedAt"
        
        val privateKey = keyStore.getKey(keyAlias, null) as? PrivateKey
            ?: throw IllegalStateException("No private key available")
        
        val signature = Signature.getInstance("SHA256withECDSA").apply {
            initSign(privateKey)
            update(dataToSign.toByteArray(Charsets.UTF_8))
        }
        
        val signatureBytes = signature.sign()
        val signatureBase64 = Base64.encodeToString(signatureBytes, Base64.NO_WRAP)
        
        return SignedChallenge(
            signature = signatureBase64,
            signedAt = signedAt,
            nonce = nonce
        )
    }
    
    /**
     * Ensure the keypair exists, generating if necessary
     */
    private fun ensureKeyPair() {
        if (!keyStore.containsAlias(keyAlias)) {
            generateKeyPair()
        }
    }
    
    /**
     * Generate a new EC P-256 keypair in the Android Keystore
     */
    private fun generateKeyPair() {
        Log.i(tag, "Generating new device keypair")
        
        val keyPairGenerator = KeyPairGenerator.getInstance(
            KeyProperties.KEY_ALGORITHM_EC,
            "AndroidKeyStore"
        )
        
        val parameterSpec = KeyGenParameterSpec.Builder(
            keyAlias,
            KeyProperties.PURPOSE_SIGN or KeyProperties.PURPOSE_VERIFY
        ).apply {
            setAlgorithmParameterSpec(ECGenParameterSpec("secp256r1"))
            setDigests(KeyProperties.DIGEST_SHA256)
            // Require user auth for extra security (optional, can be removed if too restrictive)
            // setUserAuthenticationRequired(true)
            // setUserAuthenticationValidityDurationSeconds(300)
        }.build()
        
        keyPairGenerator.initialize(parameterSpec)
        keyPairGenerator.generateKeyPair()
        
        Log.i(tag, "Device keypair generated successfully")
    }
    
    /**
     * Delete the keypair (for testing/reset)
     */
    fun deleteKeyPair() {
        if (keyStore.containsAlias(keyAlias)) {
            keyStore.deleteEntry(keyAlias)
            Log.i(tag, "Device keypair deleted")
        }
    }
    
    data class SignedChallenge(
        val signature: String,
        val signedAt: Long,
        val nonce: String
    )
}
