package app.closer.crypto

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

/**
 * Stateless helper that encrypts/decrypts individual Firestore field values.
 *
 * Wire format: "enc:v1:{base64(tinkCiphertext)}"
 * Plaintext values (no prefix) pass through unchanged so legacy data works.
 *
 * AAD = coupleId bytes -- binds ciphertext to the couple and prevents
 * copy-paste of one couple's ciphertext into another couple's document.
 */
@Singleton
class FieldEncryptor @Inject constructor() {

    fun encrypt(plaintext: String, aead: Aead, coupleId: String): String {
        val cipher = aead.encrypt(
            plaintext.toByteArray(Charsets.UTF_8),
            coupleId.toByteArray(Charsets.UTF_8)
        )
        return PREFIX + Base64.getEncoder().encodeToString(cipher)
    }

    fun encryptNullable(value: String?, aead: Aead, coupleId: String): String? =
        value?.let { encrypt(it, aead, coupleId) }

    /**
     * Decrypts if the value has the enc:v1: prefix; returns the original string otherwise.
     * Returns null when [value] is null or [aead] is null and the value is encrypted.
     */
    fun decrypt(value: String?, aead: Aead?, coupleId: String): String? {
        if (value == null) return null
        if (!value.startsWith(PREFIX)) return value
        if (aead == null) return null
        return runCatching {
            val cipher = Base64.getDecoder().decode(value.removePrefix(PREFIX))
            aead.decrypt(cipher, coupleId.toByteArray(Charsets.UTF_8))
                .toString(Charsets.UTF_8)
        }.getOrNull()
    }

    fun isEncrypted(value: String?): Boolean = value?.startsWith(PREFIX) == true

    companion object {
        const val PREFIX = "enc:v1:"
    }
}
