#include "generic_sound_column.h"

#include "application.h"
#include "httplib.h"

namespace zsy
{
    GenericSoundColumn::GenericSoundColumn(const SoundColumnProperties &config): config(config)
    {
        Application::eventManager->subscribe(config.sn + "/play", [this](const EventManager::Event &event)
        {
            if (!event.data.has_value()) return;
            auto jsonData = event.data.value();

            LOGGER_INFO("播放语音：{}", jsonData.dump());
            const auto req = jsonData.get<PlayVoiceReq>();
            this->play(req.text);
        });
        static auto subscribed = []
        {
            auto cli = Application::mqttCliHolder->remoteCli();
            auto clientId = cli->getClientId();
            if (cli)
            {
                Application::eventManager->subscribe(clientId + "/" + clientId + "/1/voice", [](const EventManager::Event &event)
                {
                    if (!event.data.has_value())
                    {
                        LOGGER_ERROR("语音播放请求参数错误");
                        return;
                    }
                    auto jsonData = event.data.value();

                    LOGGER_INFO("收到语音播放请求：{}", jsonData.dump());
                    const auto req = jsonData.get<PlayVoiceReq>();
                    auto soundColumn = Application::deviceHolder->getSoundColumn(req.deviceNo);
                    if (!soundColumn)
                    {
                        LOGGER_ERROR("未找到对应的音柱");
                        return;
                    }
                    auto sn = soundColumn->getSn();

                    Application::eventManager->publish(sn + "/play", jsonData.dump());
                });
            } else
            {
                LOGGER_ERROR("未找到 MQTT 远程客户端");
            }
            return true;
        }();
    }

    void GenericSoundColumn::play(const std::string &content)
    {
        try
        {
            LOGGER_INFO("正在播放语音，设备名称：{}", config.name);

            LOGGER_INFO("播放内容：{}", content);
            httplib::Headers headers = {
                {"Content-Type", "application/json"}
            };

            nlohmann::json data{
                {"loop", {{"times", 2}, {"gap", 2}}},
                {"prompt", true},
                {"queue", true},
                {"rcn", "0"},
                {"rdn", "0"},
                {"reg", 0},
                {"speed", 50},
                {"sync", true},
                {"text", convert(content)},
                {"vcn", "xiaoyan"},
                {"volume", 100}
            };
            auto body = data.dump();
            LOGGER_INFO("播放语音：{}{} {}", config.server, config.path, body);

            httplib::Client cli(config.server);
            cli.set_connection_timeout(5);
            cli.set_read_timeout(10);
            cli.set_write_timeout(10);

            auto response = cli.Post(config.path.c_str(), headers, body, "application/json");

            if (response)
            {
                LOGGER_INFO("语音播放结果：{}", response->body);
                const int status = response->status;
                if (status >= 300 || status < 200)
                {
                    LOGGER_ERROR("语音播放失败，HTTP状态码：{}", status);
                } else
                {
                    auto json = nlohmann::json::parse(response->body);
                    auto result = json.get<PlaySoundColumnResult>();
                    if (result.code == 200)
                    {
                        LOGGER_INFO("语音播放成功");
                    } else
                    {
                        LOGGER_ERROR("语音播放失败，错误：{}", result.message);
                    }
                }
            } else
            {
                LOGGER_ERROR("语音播放失败，错误：{}", httplib::to_string(response.error()));
            }
        } catch (const std::exception &e)
        {
            LOGGER_ERROR("语音播放失败，错误：{}", e.what());
        }
        catch (...)
        {
            LOGGER_ERROR("未知异常，语音播放失败");
        }
    }

    std::string GenericSoundColumn::getSn()
    {
        return config.sn;
    }
} // zsy
