// CRITICAL ORDER: Include system headers before local headers to avoid macro conflicts
#include <nlohmann/json.hpp>
#include <cstdlib>
#include <memory>
#include <string>
#include <queue>
#include <fstream>

// Include VoiceService.hpp BEFORE spdlog to avoid logger macro conflicts
#include "VoiceService.hpp"
#include "STTService.hpp"

// Include spdlog after VoiceService.hpp
#include <spdlog/sinks/stdout_color_sinks.h>

namespace celuna {

VoiceService::VoiceService() {
    m_logger = spdlog::get("VoiceService");
    if (!m_logger) {
        m_logger = spdlog::stdout_color_mt("VoiceService");
    }
}

bool VoiceService::initialize(grove::IIO* io) {
    m_io = io;

    // Create TTS engine
    m_ttsEngine = TTSEngineFactory::create();
    if (m_ttsEngine && m_ttsEngine->isAvailable()) {
        m_ttsEngine->setRate(m_ttsRate);
        m_ttsEngine->setVolume(m_ttsVolume);
        m_logger->info("TTS engine initialized");
    } else {
        m_logger->warn("TTS engine not available");
    }

    if (m_io) {
        grove::SubscriptionConfig config;
        m_io->subscribe("voice:speak", config);
        m_io->subscribe("voice:stop", config);
        m_io->subscribe("voice:listen", config);
    }

    m_logger->info("VoiceService initialized");
    return true;
}

void VoiceService::configureTTS(bool enabled, int rate, int volume) {
    m_ttsEnabled = enabled;
    m_ttsRate = rate;
    m_ttsVolume = volume;

    if (m_ttsEngine) {
        m_ttsEngine->setRate(rate);
        m_ttsEngine->setVolume(volume);
    }
}

void VoiceService::configureSTT(bool enabled, const std::string& language,
                                const std::string& apiKey) {
    m_sttEnabled = enabled;
    m_language = language;

    if (!apiKey.empty()) {
        m_sttEngine = STTEngineFactory::create(apiKey);
        if (m_sttEngine) {
            m_sttEngine->setLanguage(language);
            m_logger->info("STT engine configured");
        }
    }
}

void VoiceService::process() {
    processMessages();
    processSpeakQueue();
}

void VoiceService::processMessages() {
    if (!m_io) return;

    while (m_io->hasMessages() > 0) {
        auto msg = m_io->pullMessage();

        if (msg.topic == "voice:speak" && msg.data) {
            handleSpeakRequest(*msg.data);
        }
        else if (msg.topic == "voice:stop") {
            if (m_ttsEngine) {
                m_ttsEngine->stop();
            }
            // Clear queue
            while (!m_speakQueue.empty()) m_speakQueue.pop();
        }
        else if (msg.topic == "voice:listen" && m_sttEnabled && m_sttEngine) {
            // STT would be handled here
            // For now just log
            m_logger->debug("STT listen requested");
        }
    }
}

void VoiceService::handleSpeakRequest(const grove::IDataNode& data) {
    std::string text = data.getString("text", "");
    bool priority = data.getBool("priority", false);

    if (text.empty()) return;

    if (priority) {
        // Clear queue and stop current speech
        while (!m_speakQueue.empty()) m_speakQueue.pop();
        if (m_ttsEngine) m_ttsEngine->stop();
    }

    m_speakQueue.push(text);
}

void VoiceService::processSpeakQueue() {
    if (!m_ttsEnabled || !m_ttsEngine || m_speakQueue.empty()) return;

    // Only speak if not currently speaking
    if (!m_ttsEngine->isSpeaking() && !m_speakQueue.empty()) {
        std::string text = m_speakQueue.front();
        m_speakQueue.pop();
        speak(text);
    }
}

void VoiceService::speak(const std::string& text) {
    if (!m_ttsEngine || !m_ttsEnabled) return;

    // Publish speaking started
    if (m_io) {
        auto event = std::unique_ptr<grove::IDataNode>(
            new grove::JsonDataNode("event")
        );
        event->setString("text", text.size() > 100 ? text.substr(0, 100) + "..." : text);
        m_io->publish("voice:speaking_started", std::move(event));
    }

    m_ttsEngine->speak(text, true);
    m_totalSpoken++;

    m_logger->debug("Speaking");
}

// Phase 7: New STT configuration with full config support
void VoiceService::configureSTT(const nlohmann::json& sttConfig) {
    m_logger->info("[VoiceService] Configuring STT service (Phase 7)");

    // Extract enabled flag
    bool enabled = false;
    if (sttConfig.contains("active_mode")) {
        const auto& activeMode = sttConfig["active_mode"];
        enabled = activeMode.value("enabled", true);
    }

    m_sttEnabled = enabled;

    if (!enabled) {
        m_logger->info("[VoiceService] STT disabled in config");
        return;
    }

    // Create and start STT service
    m_sttService = std::make_unique<STTService>(sttConfig);

    if (!m_sttService->start()) {
        m_logger->error("[VoiceService] Failed to start STT service");
        m_sttService.reset();
        return;
    }

    m_logger->info("[VoiceService] STT service started");

    // Setup callbacks for transcription events
    // Note: For MVP Milestone 1, we don't start streaming yet
    // This will be implemented in Milestone 2 (passive mode)
}

// STT event handlers (Phase 7)
void VoiceService::handleKeyword(const std::string& keyword) {
    m_logger->info("[VoiceService] Keyword detected");

    // Publish keyword detection event
    if (m_io) {
        auto event = std::unique_ptr<grove::IDataNode>(
            new grove::JsonDataNode("event")
        );
        event->setString("keyword", keyword);
        event->setInt("timestamp", static_cast<int>(std::time(nullptr)));
        m_io->publish("voice:keyword_detected", std::move(event));
    }

    // Auto-switch to active mode (Phase 7.2)
    if (m_sttService) {
        m_sttService->setMode(STTMode::ACTIVE);
    }
}

void VoiceService::handleTranscription(const std::string& text, STTMode mode) {
    m_logger->info("[VoiceService] Transcription received");

    // Publish transcription event
    if (m_io) {
        std::string modeStr = (mode == STTMode::PASSIVE ? "passive" : "active");
        auto event = std::unique_ptr<grove::IDataNode>(
            new grove::JsonDataNode("event")
        );
        event->setString("text", text);
        event->setString("mode", modeStr);
        event->setInt("timestamp", static_cast<int>(std::time(nullptr)));
        m_io->publish("voice:transcription", std::move(event));
    }
}

void VoiceService::shutdown() {
    if (m_ttsEngine) {
        m_ttsEngine->stop();
    }

    if (m_sttService) {
        m_sttService->stop();
    }

    m_logger->info("[VoiceService] Shutdown");
}

bool VoiceService::loadConfig(const std::string& configPath) {
    try {
        std::ifstream file(configPath);
        if (!file.is_open()) {
            m_logger->warn("[VoiceService] Config file not found: {}", configPath);
            return false;
        }

        nlohmann::json config;
        file >> config;

        // Load TTS config
        if (config.contains("tts")) {
            const auto& ttsConfig = config["tts"];
            m_ttsEnabled = ttsConfig.value("enabled", true);
            m_ttsRate = ttsConfig.value("rate", 0);
            m_ttsVolume = ttsConfig.value("volume", 80);
        }

        // Load STT config (Phase 7 format)
        if (config.contains("stt")) {
            configureSTT(config["stt"]);
        }

        m_logger->info("[VoiceService] Config loaded from {}", configPath);
        return true;

    } catch (const std::exception& e) {
        m_logger->error("[VoiceService] Failed to load config: {}", e.what());
        return false;
    }
}

std::string VoiceService::transcribeFileSync(
    const std::string& filePath,
    const std::string& language
) {
    m_logger->info("[VoiceService] transcribeFileSync: {}", filePath);

    if (!m_sttService) {
        throw std::runtime_error("STT service not initialized");
    }

    // Use STT service to transcribe file synchronously
    // Note: This requires STT service to support file transcription
    // For MVP, we'll throw not implemented
    throw std::runtime_error("transcribeFileSync not yet implemented - STT service needs file transcription support");
}

bool VoiceService::textToSpeechSync(
    const std::string& text,
    const std::string& outputFile,
    const std::string& voice
) {
    m_logger->info("[VoiceService] textToSpeechSync: {} -> {}", text.substr(0, 50), outputFile);

    if (!m_ttsEngine) {
        throw std::runtime_error("TTS engine not initialized");
    }

    // For MVP, we don't support saving to file yet
    // The TTS engine currently only speaks directly
    throw std::runtime_error("textToSpeechSync file output not yet implemented - TTS engine needs file output support");
}

} // namespace celuna
