#pragma once

#ifdef _WIN32

#include "ITTSEngine.hpp"
#include <spdlog/spdlog.h>
#include <Windows.h>
#include <sapi.h>
#include <sphelper.h>
#include <memory>

namespace celuna {

/**
 * @brief Windows SAPI Text-to-Speech engine
 */
class SAPITTSEngine : public ITTSEngine {
public:
    SAPITTSEngine() {
        m_logger = spdlog::get("SAPITTS");
        if (!m_logger) {
            m_logger = spdlog::stdout_color_mt("SAPITTS");
        }

        // Initialize COM
        HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
        if (FAILED(hr) && hr != RPC_E_CHANGED_MODE) {
            m_logger->error("Failed to initialize COM: {}", hr);
            return;
        }
        m_comInitialized = true;

        // Create voice
        hr = CoCreateInstance(CLSID_SpVoice, nullptr, CLSCTX_ALL,
                             IID_ISpVoice, (void**)&m_voice);
        if (FAILED(hr)) {
            m_logger->error("Failed to create SAPI voice: {}", hr);
            return;
        }

        m_available = true;
        m_logger->info("SAPI TTS initialized");
    }

    ~SAPITTSEngine() override {
        if (m_voice) {
            m_voice->Release();
            m_voice = nullptr;
        }
        if (m_comInitialized) {
            CoUninitialize();
        }
    }

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

        // Convert to wide string
        int size = MultiByteToWideChar(CP_UTF8, 0, text.c_str(), -1, nullptr, 0);
        std::wstring wtext(size, 0);
        MultiByteToWideChar(CP_UTF8, 0, text.c_str(), -1, &wtext[0], size);

        DWORD flags = async ? SPF_ASYNC : SPF_DEFAULT;
        flags |= SPF_PURGEBEFORESPEAK;  // Stop current speech first

        m_voice->Speak(wtext.c_str(), flags, nullptr);
        m_logger->debug("Speaking: {}", text.substr(0, 50));
    }

    void stop() override {
        if (m_voice) {
            m_voice->Speak(nullptr, SPF_PURGEBEFORESPEAK, nullptr);
        }
    }

    void setRate(int rate) override {
        if (m_voice) {
            // SAPI rate is -10 to 10
            rate = std::max(-10, std::min(10, rate));
            m_voice->SetRate(rate);
        }
    }

    void setVolume(int volume) override {
        if (m_voice) {
            // SAPI volume is 0 to 100
            volume = std::max(0, std::min(100, volume));
            m_voice->SetVolume(static_cast<USHORT>(volume));
        }
    }

    bool isSpeaking() const override {
        if (!m_voice) return false;

        SPVOICESTATUS status;
        m_voice->GetStatus(&status, nullptr);
        return status.dwRunningState == SPRS_IS_SPEAKING;
    }

    bool isAvailable() const override {
        return m_available;
    }

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

private:
    ISpVoice* m_voice = nullptr;
    bool m_comInitialized = false;
    bool m_available = false;
    std::shared_ptr<spdlog::logger> m_logger;
};

} // namespace celuna

#endif // _WIN32
