package com.rosetta.messenger.network

import android.util.Log
import org.webrtc.FrameDecryptor
import org.webrtc.FrameEncryptor

/**
 * XChaCha20-based E2EE compatible with Rosetta Desktop.
 *
 * Desktop encrypts audio frames using XChaCha20 (libsodium) with a nonce
 * derived from the RTP timestamp.  The shared key is computed as
 * nacl.box.before(peerPub, ownSecret) = HSalsa20(zeros, X25519(sk, pk)).
 *
 * This class provides:
 *  - [hsalsa20] — applies HSalsa20 to a raw X25519 shared secret,
 *    producing the same key as nacl.box.before().
 *  - [Encryptor] / [Decryptor] — WebRTC FrameEncryptor / FrameDecryptor
 *    that use XChaCha20 matching the Desktop implementation.
 */
object XChaCha20E2EE {

    private const val TAG = "XChaCha20E2EE"

    var nativeLoaded: Boolean = false
        private set

    private var crashFilePath: String? = null

    fun initWithContext(context: android.content.Context) {
        if (!nativeLoaded) return
        try {
            val dir = java.io.File(context.filesDir, "crash_reports")
            if (!dir.exists()) dir.mkdirs()
            val path = java.io.File(dir, "native_crash.txt").absolutePath
            crashFilePath = path
            nativeInstallCrashHandler(path)
            Log.i(TAG, "Native crash handler installed → $path")
        } catch (e: Throwable) {
            Log.e(TAG, "Failed to install native crash handler", e)
        }
    }

    init {
        try {
            System.loadLibrary("rosetta_e2ee")
            nativeLoaded = true
            Log.i(TAG, "Native library loaded successfully")
        } catch (e: UnsatisfiedLinkError) {
            Log.e(TAG, "Failed to load native library rosetta_e2ee", e)
        }
    }

    /**
     * HSalsa20(zeros_16, rawDhShared, sigma) — converts a raw X25519
     * shared secret into the NaCl box-before shared key.
     */
    fun hsalsa20(rawDhShared: ByteArray): ByteArray {
        require(nativeLoaded) { "Native library not loaded" }
        require(rawDhShared.size >= 32) { "Raw DH shared secret must be >= 32 bytes" }
        return nativeHSalsa20(rawDhShared)
    }

    /** WebRTC [FrameEncryptor] backed by native XChaCha20. */
    class Encryptor(key: ByteArray) : FrameEncryptor {
        private val nativePtr: Long

        init {
            require(nativeLoaded) { "Native library not loaded" }
            nativePtr = nativeCreateEncryptor(key)
            Log.i(TAG, "Encryptor created, ptr=0x${nativePtr.toString(16)}")
        }

        override fun getNativeFrameEncryptor(): Long = nativePtr

        fun frameCount(): Int = if (nativePtr != 0L) nativeGetEncryptorFrameCount(nativePtr) else -1

        fun dispose() {
            if (nativePtr != 0L) nativeReleaseEncryptor(nativePtr)
        }
    }

    /** WebRTC [FrameDecryptor] backed by native XChaCha20. */
    class Decryptor(key: ByteArray) : FrameDecryptor {
        private val nativePtr: Long

        init {
            require(nativeLoaded) { "Native library not loaded" }
            nativePtr = nativeCreateDecryptor(key)
            Log.i(TAG, "Decryptor created, ptr=0x${nativePtr.toString(16)}")
        }

        override fun getNativeFrameDecryptor(): Long = nativePtr

        fun frameCount(): Int = if (nativePtr != 0L) nativeGetDecryptorFrameCount(nativePtr) else -1
        fun badStreak(): Int = if (nativePtr != 0L) nativeGetDecryptorBadStreak(nativePtr) else -1

        fun dispose() {
            if (nativePtr != 0L) nativeReleaseDecryptor(nativePtr)
        }
    }

    /* ── JNI ─────────────────────────────────────────────────── */

    @JvmStatic private external fun nativeHSalsa20(rawDh: ByteArray): ByteArray
    @JvmStatic private external fun nativeCreateEncryptor(key: ByteArray): Long
    @JvmStatic private external fun nativeReleaseEncryptor(ptr: Long)
    @JvmStatic private external fun nativeGetEncryptorFrameCount(ptr: Long): Int
    @JvmStatic private external fun nativeCreateDecryptor(key: ByteArray): Long
    @JvmStatic private external fun nativeReleaseDecryptor(ptr: Long)
    @JvmStatic private external fun nativeGetDecryptorFrameCount(ptr: Long): Int
    @JvmStatic private external fun nativeGetDecryptorBadStreak(ptr: Long): Int
    @JvmStatic private external fun nativeInstallCrashHandler(path: String)
    @JvmStatic external fun nativeOpenDiagFile(path: String)
    @JvmStatic external fun nativeCloseDiagFile()
}
