#pragma once

#ifdef __linux__

#include "ITTSEngine.hpp"
#include <spdlog/spdlog.h>
#include <spdlog/sinks/stdout_color_sinks.h>
#include <cstdlib>
#include <cstdio>
#include <memory>
#include <thread>
#include <atomic>

namespace celuna {

/**
 * @brief Linux espeak-ng Text-to-Speech engine
 *
 * Uses espeak-ng command line tool. Falls back gracefully if not installed.
 */
class EspeakTTSEngine : public ITTSEngine {
public:
    EspeakTTSEngine() {
        m_logger = spdlog::get("EspeakTTS");
        if (!m_logger) {
            m_logger = spdlog::stdout_color_mt("EspeakTTS");
        }

        // Check if espeak-ng is available
        m_available = (system("which espeak-ng > /dev/null 2>&1") == 0);
        if (!m_available) {
            // Try espeak as fallback
            m_available = (system("which espeak > /dev/null 2>&1") == 0);
            if (m_available) {
                m_command = "espeak";
            }
        }

        if (m_available) {
            m_logger->info("espeak TTS initialized ({})", m_command);
        } else {
            m_logger->warn("espeak not available. Install with: sudo apt install espeak-ng");
        }
    }

    ~EspeakTTSEngine() override {
        stop();
    }

    void speak(const std::string& text, bool async = true) override {
        if (!m_available) return;

        stop();  // Stop any current speech

        // Build command
        std::string cmd = m_command;
        cmd += " -s " + std::to_string(m_rate);
        cmd += " -a " + std::to_string(m_volume);
        cmd += " -v " + m_voice;
        cmd += " \"" + escapeQuotes(text) + "\"";

        if (async) {
            cmd += " &";
            m_speaking = true;
            system(cmd.c_str());
        } else {
            m_speaking = true;
            system(cmd.c_str());
            m_speaking = false;
        }

        m_logger->debug("Speaking: {}", text.substr(0, 50));
    }

    void stop() override {
        if (m_speaking) {
            system("pkill -9 espeak 2>/dev/null");
            system("pkill -9 espeak-ng 2>/dev/null");
            m_speaking = false;
        }
    }

    void setRate(int rate) override {
        // espeak rate is words per minute, default ~175
        // Map -10..10 to 80..400
        m_rate = 175 + (rate * 20);
        m_rate = std::max(80, std::min(400, m_rate));
    }

    void setVolume(int volume) override {
        // espeak volume is 0-200, default 100
        m_volume = volume * 2;
        m_volume = std::max(0, std::min(200, m_volume));
    }

    bool isSpeaking() const override {
        return m_speaking;
    }

    bool isAvailable() const override {
        return m_available;
    }

    std::string getEngineName() const override {
        return "espeak";
    }

    void setVoice(const std::string& voice) {
        m_voice = voice;
    }

private:
    std::string m_command = "espeak-ng";
    std::string m_voice = "fr";  // Default French voice
    int m_rate = 175;
    int m_volume = 100;
    bool m_available = false;
    std::atomic<bool> m_speaking{false};
    std::shared_ptr<spdlog::logger> m_logger;

    std::string escapeQuotes(const std::string& text) {
        std::string result;
        for (char c : text) {
            if (c == '"') result += "\\\"";
            else if (c == '`') result += "\\`";
            else if (c == '$') result += "\\$";
            else result += c;
        }
        return result;
    }
};

} // namespace celuna

#endif // __linux__
