#include "Pipeline.h"
#include "../audio/AudioCapture.h"
#include "../audio/AudioBuffer.h"
#include "../api/WhisperClient.h"
#include "../api/ClaudeClient.h"
#include "../ui/TranslationUI.h"
#include "../utils/Config.h"
#include <iostream>
#include <iomanip>
#include <sstream>
#include <chrono>
#include <filesystem>
#include <cmath>
#include <algorithm>

namespace secondvoice {

Pipeline::Pipeline() = default;

Pipeline::~Pipeline() {
    stop();
}

bool Pipeline::initialize() {
    auto& config = Config::getInstance();

    // Initialize audio capture with VAD-based segmentation
    audio_capture_ = std::make_unique<AudioCapture>(
        config.getAudioConfig().sample_rate,
        config.getAudioConfig().channels
    );

    std::cout << "[Pipeline] VAD-based audio segmentation enabled" << std::endl;

    if (!audio_capture_->initialize()) {
        std::cerr << "Failed to initialize audio capture" << std::endl;
        return false;
    }

    // Initialize API clients
    whisper_client_ = std::make_unique<WhisperClient>(config.getOpenAIKey());
    claude_client_ = std::make_unique<ClaudeClient>(config.getAnthropicKey());

    // Initialize UI
    ui_ = std::make_unique<TranslationUI>(
        config.getUIConfig().window_width,
        config.getUIConfig().window_height
    );

    if (!ui_->initialize()) {
        std::cerr << "Failed to initialize UI" << std::endl;
        return false;
    }

    // Initialize full recording buffer
    full_recording_ = std::make_unique<AudioBuffer>(
        config.getAudioConfig().sample_rate,
        config.getAudioConfig().channels
    );

    // Create recordings directory if it doesn't exist
    std::filesystem::create_directories(config.getRecordingConfig().output_directory);

    return true;
}

bool Pipeline::start() {
    if (running_) {
        return false;
    }

    running_ = true;

    // Start background threads
    audio_thread_ = std::thread(&Pipeline::audioThread, this);
    processing_thread_ = std::thread(&Pipeline::processingThread, this);

    return true;
}

void Pipeline::stop() {
    if (!running_) {
        return;
    }

    running_ = false;

    // Stop audio capture
    if (audio_capture_) {
        audio_capture_->stop();
    }

    // Shutdown queue
    audio_queue_.shutdown();

    // Wait for background threads
    if (audio_thread_.joinable()) {
        audio_thread_.join();
    }
    if (processing_thread_.joinable()) {
        processing_thread_.join();
    }

    // Save full recording
    auto& config = Config::getInstance();
    if (config.getRecordingConfig().save_audio && full_recording_) {
        auto now = std::chrono::system_clock::now();
        auto time_t = std::chrono::system_clock::to_time_t(now);
        std::stringstream ss;
        ss << config.getRecordingConfig().output_directory << "/"
           << "recording_" << std::put_time(std::localtime(&time_t), "%Y%m%d_%H%M%S")
           << ".wav";

        if (full_recording_->saveToWav(ss.str())) {
            std::cout << "Recording saved to: " << ss.str() << std::endl;
        } else {
            std::cerr << "Failed to save recording" << std::endl;
        }
    }
}

void Pipeline::audioThread() {
    auto& config = Config::getInstance();

    audio_capture_->start([this, &config](const std::vector<float>& audio_data) {
        if (!running_) return;

        // Add to full recording
        full_recording_->addSamples(audio_data);

        // Push to processing queue
        AudioChunk chunk;
        chunk.data = audio_data;
        chunk.sample_rate = config.getAudioConfig().sample_rate;
        chunk.channels = config.getAudioConfig().channels;

        audio_queue_.push(std::move(chunk));
    });

    // Keep thread alive while recording
    auto start_time = std::chrono::steady_clock::now();
    while (running_ && audio_capture_->isRecording()) {
        std::this_thread::sleep_for(std::chrono::milliseconds(100));

        // Update duration
        auto now = std::chrono::steady_clock::now();
        recording_duration_ = std::chrono::duration_cast<std::chrono::seconds>(now - start_time).count();
    }
}

void Pipeline::processingThread() {
    auto& config = Config::getInstance();

    while (running_) {
        auto chunk_opt = audio_queue_.wait_and_pop();
        if (!chunk_opt.has_value()) {
            break;  // Queue shutdown
        }

        auto& chunk = chunk_opt.value();
        float duration = static_cast<float>(chunk.data.size()) / (chunk.sample_rate * chunk.channels);
        std::cout << "[Processing] Speech segment: " << duration << "s" << std::endl;

        // Transcribe with Whisper
        auto whisper_result = whisper_client_->transcribe(
            chunk.data,
            chunk.sample_rate,
            chunk.channels,
            config.getWhisperConfig().model,
            config.getWhisperConfig().language,
            config.getWhisperConfig().temperature,
            config.getWhisperConfig().prompt,
            config.getWhisperConfig().response_format
        );

        if (!whisper_result.has_value()) {
            std::cerr << "Whisper transcription failed" << std::endl;
            continue;
        }

        // Filter out Whisper hallucinations
        std::string text = whisper_result->text;

        // Trim whitespace
        size_t start = text.find_first_not_of(" \t\n\r");
        size_t end = text.find_last_not_of(" \t\n\r");
        if (start == std::string::npos) {
            std::cout << "[Skip] Empty transcription" << std::endl;
            continue;
        }
        text = text.substr(start, end - start + 1);

        // Skip known hallucinations and garbage
        // Whisper hallucinates these when given silence/noise
        bool is_garbage = false;
        if (text.length() < 4) {
            is_garbage = true;
        } else if (
            // Common Whisper hallucinations
            text.find("Tingting") != std::string::npos ||
            text.find("tingting") != std::string::npos ||
            text.find("婷婷") != std::string::npos ||
            text.find("Thank you") != std::string::npos ||
            text.find("thanks for watching") != std::string::npos ||
            text.find("Thanks for watching") != std::string::npos ||
            text.find("Subscribe") != std::string::npos ||
            text.find("subscribe") != std::string::npos ||
            text.find("請訂閱") != std::string::npos ||
            text.find("请订阅") != std::string::npos ||
            text.find("訂閱") != std::string::npos ||
            text.find("订阅") != std::string::npos ||
            text.find("Amara.org") != std::string::npos ||
            text.find("amara.org") != std::string::npos ||
            text.find("字幕") != std::string::npos ||
            text.find("subtitle") != std::string::npos ||
            text.find("Subtitle") != std::string::npos ||
            text.find("谢谢观看") != std::string::npos ||
            text.find("謝謝觀看") != std::string::npos ||
            text.find("感谢收看") != std::string::npos ||
            text.find("感謝收看") != std::string::npos ||
            text.find("下期再见") != std::string::npos ||
            text.find("下期再見") != std::string::npos ||
            text.find("再见") != std::string::npos ||
            text.find("再見") != std::string::npos ||
            text.find("music") != std::string::npos ||
            text.find("Music") != std::string::npos ||
            text.find("♪") != std::string::npos ||
            text.find("silenc") != std::string::npos ||  // silence, silencieux
            text.find("Silenc") != std::string::npos ||
            text.find("...") == 0 ||
            // Repetitive single words/sounds
            text == "Bonjour" ||
            text == "Hello" ||
            text == "Hi" ||
            text == "你好" ||
            text == "好" ||
            text == "嗯" ||
            text == "啊" ||
            text == "哈" ||
            text == "呵呵" ||
            text == "哈哈" ||
            text == "嘻嘻" ||
            text == "Hmm" ||
            text == "Huh" ||
            text == "Um" ||
            text == "Uh") {
            is_garbage = true;
        } else {
            bool has_content = false;
            for (char c : text) {
                if (std::isalnum(static_cast<unsigned char>(c)) || (c & 0x80)) {
                    has_content = true;
                    break;
                }
            }
            if (!has_content) is_garbage = true;
        }

        if (is_garbage) {
            std::cout << "[Skip] Filtered: " << text << std::endl;
            continue;
        }

        // Track audio cost
        if (ui_) {
            ui_->addAudioCost(duration);
        }

        // Translate with Claude
        auto claude_result = claude_client_->translate(
            text,
            config.getClaudeConfig().system_prompt,
            config.getClaudeConfig().max_tokens,
            config.getClaudeConfig().temperature
        );

        if (!claude_result.has_value()) {
            std::cerr << "Claude translation failed" << std::endl;
            continue;
        }

        // Track Claude cost
        if (ui_) {
            ui_->addClaudeCost();
        }

        // Simple accumulation
        if (!accumulated_chinese_.empty()) {
            accumulated_chinese_ += " ";
            accumulated_french_ += " ";
        }
        accumulated_chinese_ += text;
        accumulated_french_ += claude_result->text;

        std::cout << "[Accumulated CN] " << accumulated_chinese_ << std::endl;
        std::cout << "[Accumulated FR] " << accumulated_french_ << std::endl;

        // Update UI
        ui_->setAccumulatedText(accumulated_chinese_, accumulated_french_);
        ui_->addTranslation(text, claude_result->text);

        std::cout << "CN: " << text << std::endl;
        std::cout << "FR: " << claude_result->text << std::endl;
        std::cout << "---" << std::endl;
    }
}

void Pipeline::update() {
    if (!ui_) return;

    // Sync VAD thresholds from UI to AudioCapture
    if (audio_capture_) {
        audio_capture_->setVadThresholds(
            ui_->getVadThreshold(),
            ui_->getVadPeakThreshold()
        );

        // Update UI with audio levels
        ui_->setCurrentRMS(audio_capture_->getCurrentRMS());
        ui_->setCurrentPeak(audio_capture_->getCurrentPeak());
    }

    ui_->setRecordingDuration(recording_duration_);
    ui_->setProcessingStatus(audio_capture_ && audio_capture_->isSpeechDetected() ? "Recording speech..." : "Listening...");
    ui_->render();

    // Check if stop was requested
    if (ui_->isStopRequested()) {
        running_ = false;
    }

    // Check if clear was requested
    if (ui_->isClearRequested()) {
        clearAccumulated();
        ui_->resetClearRequest();
    }
}

bool Pipeline::shouldClose() const {
    return ui_ ? ui_->shouldClose() : true;
}

void Pipeline::clearAccumulated() {
    accumulated_chinese_.clear();
    accumulated_french_.clear();
    if (ui_) {
        ui_->setAccumulatedText("", "");
    }
    std::cout << "[Pipeline] Cleared accumulated text" << std::endl;
}

} // namespace secondvoice
