package com.phostt

/**
 * Kotlin JNI bridge for the phostt on-device Vietnamese STT engine.
 *
 * This object loads the native `libphostt.so` (built via cargo-ndk) and exposes
 * externals that map 1:1 to the C-ABI functions in `src/ffi.rs`.
 *
 * Usage (file transcription):
 * ```kotlin
 * val enginePtr = PhosttBridge.engineNew(modelDir)
 * if (enginePtr == 0L) throw RuntimeException("Failed to load engine")
 * try {
 *     val text = PhosttBridge.transcribeFile(enginePtr, wavPath)
 *     println("Transcription: $text")
 * } finally {
 *     PhosttBridge.engineFree(enginePtr)
 * }
 * ```
 *
 * Usage (real-time streaming):
 * ```kotlin
 * val enginePtr = PhosttBridge.engineNew(modelDir)
 * val streamPtr = PhosttBridge.streamNew(enginePtr)
 * if (streamPtr == 0L) throw RuntimeException("Failed to create stream")
 * try {
 *     val audioChunk: ByteArray = recorder.read(...) // PCM16 LE mono
 *     val json = PhosttBridge.streamProcessChunk(enginePtr, streamPtr, audioChunk, 16000)
 *     val segments = JSONArray(json)
 *     for (i in 0 until segments.length()) {
 *         val seg = segments.getJSONObject(i)
 *         println("${seg.getString("type")}: ${seg.getString("text")}")
 *     }
 * } finally {
 *     val finalJson = PhosttBridge.streamFlush(enginePtr, streamPtr)
 *     PhosttBridge.streamFree(streamPtr)
 *     PhosttBridge.engineFree(enginePtr)
 * }
 * ```
 */
object PhosttBridge {
    init {
        System.loadLibrary("phostt")
    }

    /**
     * Load the ONNX models from [modelDir] and create an inference engine.
     *
     * @param modelDir Absolute path to the directory containing
     *                 `encoder.int8.onnx`, `decoder.onnx`, `joiner.int8.onnx`,
     *                 `bpe.model`, and `tokens.txt`.
     * @return An opaque native pointer (cast to `Long`), or `0L` on failure.
     */
    @JvmStatic
    external fun engineNew(modelDir: String): Long

    /**
     * Transcribe a WAV (or MP3/FLAC/OGG/M4A) file to text.
     *
     * @param enginePtr Pointer returned by [engineNew].
     * @param wavPath Absolute path to the audio file.
     * @return The recognized text, or an empty string on failure.
     */
    @JvmStatic
    external fun transcribeFile(enginePtr: Long, wavPath: String): String

    /**
     * Free a string previously returned by [transcribeFile] or the streaming
     * functions.
     *
     * **Note:** The Kotlin JNI glue generated by `javah` / `javac -h` normally
     * copies the `jstring` into a JVM-managed `String` object, so the C string
     * returned by Rust is immediately eligible for freeing.  If you change the
     * JNI layer to keep the raw C pointer alive (e.g. zero-copy), you must call
     * this method explicitly.
     *
     * @param ptr Raw C string pointer (as `Long`).
     */
    @JvmStatic
    external fun stringFree(ptr: Long)

    /**
     * Tear down the inference engine and release all ONNX sessions.
     *
     * @param enginePtr Pointer returned by [engineNew].
     */
    @JvmStatic
    external fun engineFree(ptr: Long)

    // -----------------------------------------------------------------------
    // Streaming API
    // -----------------------------------------------------------------------

    /**
     * Create a new real-time streaming session.
     *
     * Checks out a session triplet from the engine pool. The triplet is held
     * until [streamFree] is called.
     *
     * @param enginePtr Pointer returned by [engineNew].
     * @return An opaque stream pointer, or `0L` on failure (e.g. pool exhausted).
     */
    @JvmStatic
    external fun streamNew(enginePtr: Long): Long

    /**
     * Process a chunk of raw PCM16 audio and return partial/final segments.
     *
     * @param enginePtr Pointer returned by [engineNew].
     * @param streamPtr Pointer returned by [streamNew].
     * @param pcm16 Raw little-endian PCM16 mono bytes.
     * @param sampleRate Sample rate in Hz (e.g. 16000, 44100, 48000).
     *                   Non-16kHz input is resampled automatically.
     * @return A JSON array of segment objects, or an empty string on failure.
     *         Each object has keys: `type` ("partial" | "final"), `text`,
     *         `timestamp`, `words`.
     */
    @JvmStatic
    external fun streamProcessChunk(enginePtr: Long, streamPtr: Long, pcm16: ByteArray, sampleRate: Int): String

    /**
     * Flush the streaming state and return the final segment(s).
     *
     * @param enginePtr Pointer returned by [engineNew].
     * @param streamPtr Pointer returned by [streamNew].
     * @return A JSON array with 0 or 1 final segment, or an empty string on failure.
     */
    @JvmStatic
    external fun streamFlush(enginePtr: Long, streamPtr: Long): String

    /**
     * Free a streaming session and return its triplet to the pool.
     *
     * @param streamPtr Pointer returned by [streamNew].
     */
    @JvmStatic
    external fun streamFree(streamPtr: Long)
}
