package app.closer.crypto

import com.google.crypto.tink.KeysetHandle
import java.util.Base64
import javax.inject.Inject
import javax.inject.Singleton

/**
 * Wraps and unwraps a one-time answer key for secure transfer between partners at reveal time.
 *
 * At reveal (both partners have submitted):
 *   Alice calls [wrapForRecipient] with Bob's public key → writes "keybox:v1:..." to Firestore.
 *   Bob calls [unwrapFromSender] with his own private key → recovers Alice's one-time answer key.
 *   Bob's app can then decrypt Alice's sealed answer payload.
 *
 * Context info (ECIES HKDF label) = "{coupleId}|{questionId}|{senderUserId}|{recipientUserId}",
 * binding the wrapped key to its exact origin and destination.
 *
 * Wire format: "keybox:v1:{urlsafe-base64-no-padding}"
 *
 * The Tink primitive operations are called via [UserKeyManager] companion object functions
 * so this class has no dependency on Android Context and remains unit-testable.
 */
@Singleton
class ReleaseKeyEncryptor @Inject constructor(
    private val sealedAnswerEncryptor: SealedAnswerEncryptor
) {

    fun wrapForRecipient(
        oneTimeKey: KeysetHandle,
        recipientPublicKeyB64: String,
        coupleId: String,
        questionId: String,
        senderUserId: String,
        recipientUserId: String
    ): String {
        val keyBytes = sealedAnswerEncryptor.serializeKey(oneTimeKey).toByteArray(Charsets.UTF_8)
        val contextInfo = contextInfo(coupleId, questionId, senderUserId, recipientUserId)
        val hybrid = UserKeyManager.hybridEncryptFrom(recipientPublicKeyB64)
        val ciphertext = hybrid.encrypt(keyBytes, contextInfo)
        return KEYBOX_PREFIX + Base64.getUrlEncoder().withoutPadding().encodeToString(ciphertext)
    }

    fun unwrapFromSender(
        keyboxB64: String,
        recipientPrivateKey: KeysetHandle,
        coupleId: String,
        questionId: String,
        senderUserId: String,
        recipientUserId: String
    ): KeysetHandle {
        require(keyboxB64.startsWith(KEYBOX_PREFIX)) { "Not a keybox payload" }
        val ciphertext = Base64.getUrlDecoder().decode(keyboxB64.removePrefix(KEYBOX_PREFIX))
        val contextInfo = contextInfo(coupleId, questionId, senderUserId, recipientUserId)
        val hybrid = UserKeyManager.hybridDecryptFor(recipientPrivateKey)
        val keyJson = hybrid.decrypt(ciphertext, contextInfo).toString(Charsets.UTF_8)
        return sealedAnswerEncryptor.deserializeKey(keyJson)
    }

    private fun contextInfo(
        coupleId: String,
        questionId: String,
        senderUserId: String,
        recipientUserId: String
    ): ByteArray = "$coupleId|$questionId|$senderUserId|$recipientUserId".toByteArray(Charsets.UTF_8)

    companion object {
        const val KEYBOX_PREFIX = "keybox:v1:"
    }
}
