#pragma once

#include <string>
#include <vector>
#include <thread>
#include <mutex>
#include <atomic>
#include <functional>

struct whisper_context;

struct WhisperConfig {
    std::string model_path = "models/ggml-tiny.en.bin";
    std::string language   = "en";
    int  n_threads  = 0;      // 0 = auto (physical cores)
    bool use_gpu    = false;
    int  capture_id = 0;
    bool trim_silence = true;
};

class Transcriber {
public:
    using ResultCb = std::function<void(const std::string&)>;
    using ProgressCb = std::function<void(int)>;

    Transcriber() = default;
    ~Transcriber();

    bool preload(const WhisperConfig& cfg);
    bool reload(const WhisperConfig& cfg);
    bool is_loaded() const { return m_ctx != nullptr; }
    int  threads() const { return m_cfg.n_threads; }

    bool start_recording();
    void stop_and_transcribe();
    void cancel();

    bool  is_recording() const { return m_recording.load(); }
    bool  is_busy()      const { return m_busy.load(); }
    float get_audio_energy() const { return m_energy.load(); }
    float audio_seconds() const { return m_audio_seconds.load(); }
    float recorded_seconds() const;

    void set_result_callback(ResultCb cb) { m_on_result = std::move(cb); }
    void set_progress_callback(ProgressCb cb) { m_on_progress = std::move(cb); }
    void request_cancel() { m_abort = true; }

    void on_audio(const float* samples, int n);
    std::string transcribe_sync(std::vector<float> audio);
    static std::vector<std::string> get_audio_devices();

private:
    void transcribe_worker(std::vector<float> audio);
    std::string run_inference(std::vector<float>& audio);
    static int default_threads();

    WhisperConfig    m_cfg;
    std::mutex        m_cfg_mtx;
    whisper_context* m_ctx = nullptr;

    unsigned int       m_dev = 0;
    std::vector<float> m_capture;
    mutable std::mutex m_capture_mtx;

    std::atomic<bool>  m_recording{false};
    std::atomic<bool>  m_busy{false};
    std::atomic<float> m_energy{0.0f};
    std::atomic<float> m_audio_seconds{0.0f};
    std::atomic<bool>  m_abort{false};

    std::thread m_worker;
    ResultCb    m_on_result;
    ProgressCb  m_on_progress;

    static void s_progress(struct whisper_context*, struct whisper_state*, int p, void* ud);
    static bool s_abort(void* ud);
};
