#include "WhisperCppEngine.hpp"
#include <spdlog/spdlog.h>
#include <spdlog/sinks/stdout_color_sinks.h>
#include <fstream>
#include <cstring>

// Only include whisper.cpp headers if library is available
#ifdef HAVE_WHISPER_CPP
#include <whisper.h>
#endif

namespace celuna {

WhisperCppEngine::WhisperCppEngine(const std::string& modelPath)
    : m_modelPath(modelPath)
{
    m_logger = spdlog::get("WhisperCpp");
    if (!m_logger) {
        m_logger = spdlog::stdout_color_mt("WhisperCpp");
    }

    m_available = initialize();

    if (m_available) {
        m_logger->info("Whisper.cpp STT initialized: model={}", modelPath);
    } else {
        m_logger->warn("Whisper.cpp not available (library not compiled or model missing)");
    }
}

WhisperCppEngine::~WhisperCppEngine() {
    cleanup();
}

bool WhisperCppEngine::initialize() {
#ifdef HAVE_WHISPER_CPP
    // Check if model file exists
    std::ifstream modelCheck(m_modelPath, std::ios::binary);
    if (!modelCheck.good()) {
        m_logger->error("Whisper model not found at: {}", m_modelPath);
        return false;
    }
    modelCheck.close();

    // Initialize whisper context
    m_ctx = whisper_init_from_file(m_modelPath.c_str());
    if (!m_ctx) {
        m_logger->error("Failed to initialize Whisper context from model: {}", m_modelPath);
        return false;
    }

    m_logger->info("Whisper.cpp model loaded successfully");
    return true;
#else
    m_logger->warn("Whisper.cpp support not compiled (HAVE_WHISPER_CPP not defined)");
    return false;
#endif
}

void WhisperCppEngine::cleanup() {
#ifdef HAVE_WHISPER_CPP
    if (m_ctx) {
        whisper_free(m_ctx);
        m_ctx = nullptr;
    }
#endif
}

void WhisperCppEngine::setParameters(int threads, bool translate) {
    m_threads = threads;
    m_translate = translate;
    m_logger->debug("Whisper.cpp parameters: threads={}, translate={}", threads, translate);
}

std::string WhisperCppEngine::processAudioData(const float* audioData, size_t numSamples) {
#ifdef HAVE_WHISPER_CPP
    if (!m_ctx) {
        return "";
    }

    // Setup whisper parameters
    whisper_full_params params = whisper_full_default_params(WHISPER_SAMPLING_GREEDY);
    params.n_threads = m_threads;
    params.translate = m_translate;
    params.print_progress = false;
    params.print_special = false;
    params.print_realtime = false;
    params.print_timestamps = false;

    // Set language if specified (not "auto")
    if (m_language != "auto" && m_language.size() >= 2) {
        std::string lang2 = m_language.substr(0, 2);  // Take first 2 chars (ISO 639-1)
        params.language = lang2.c_str();
        m_logger->debug("Whisper.cpp using language: {}", lang2);
    }

    // Run full inference
    int result = whisper_full(m_ctx, params, audioData, numSamples);
    if (result != 0) {
        m_logger->error("Whisper.cpp inference failed with code: {}", result);
        return "";
    }

    // Get transcription
    std::string transcription;
    int n_segments = whisper_full_n_segments(m_ctx);
    for (int i = 0; i < n_segments; ++i) {
        const char* text = whisper_full_get_segment_text(m_ctx, i);
        if (text) {
            if (!transcription.empty()) {
                transcription += " ";
            }
            transcription += text;
        }
    }

    // Trim leading/trailing whitespace
    size_t start = transcription.find_first_not_of(" \t\n\r");
    size_t end = transcription.find_last_not_of(" \t\n\r");
    if (start != std::string::npos && end != std::string::npos) {
        transcription = transcription.substr(start, end - start + 1);
    }

    m_logger->debug("Whisper.cpp transcribed: '{}' ({} segments)", transcription, n_segments);
    return transcription;
#else
    return "";
#endif
}

std::string WhisperCppEngine::transcribe(const std::vector<float>& audioData) {
    if (!m_available || audioData.empty()) {
        return "";
    }

    m_logger->debug("Whisper.cpp transcribing {} samples", audioData.size());
    return processAudioData(audioData.data(), audioData.size());
}

std::string WhisperCppEngine::transcribeFile(const std::string& filePath) {
    if (!m_available) {
        return "";
    }

    m_logger->info("Whisper.cpp transcribing file: {}", filePath);

    // For file transcription, we'd need to:
    // 1. Read the audio file (wav format)
    // 2. Extract PCM float samples at 16kHz mono
    // 3. Call processAudioData
    //
    // whisper.cpp provides helper functions for this, but requires linking audio libraries
    m_logger->warn("Whisper.cpp file transcription not yet implemented (use transcribe() with PCM data)");
    return "";
}

void WhisperCppEngine::setLanguage(const std::string& language) {
    m_language = language;
    m_logger->info("Whisper.cpp language set to: {}", language);
}

bool WhisperCppEngine::isAvailable() const {
    return m_available;
}

std::string WhisperCppEngine::getEngineName() const {
    return "whisper-cpp";
}

} // namespace celuna
