// src/Services/AudioStreamService.h
#pragma once

#include <atomic>
#include <chrono>
#include <filesystem>
#include <memory>
#include <mutex>
#include <optional>
#include <string>
#include <utility>
#include <vector>
#include <cstdio>
#include <array>

#include <spdlog/spdlog.h>

#include "WhipClient.h"
#include "ConfigService.h"
#include "Security/TlsKeyUtil.h"

namespace snoop
{

    class AudioStreamService
    {
        std::shared_ptr<ConfigService> m_cfg;

        // WHIP
        std::unique_ptr<WhipClient> m_whip;
        std::mutex m_whipMutex;

    public:
        explicit AudioStreamService(std::shared_ptr<ConfigService> cfg)
            : m_cfg(std::move(cfg)) {}

        ~AudioStreamService() { StopWhip(); }

        // Feed encoded Opus; frames = PCM samples per channel represented by this Opus frame
        void OnOpus(const unsigned char *opusData, size_t opusBytes, int pcmFramesPerChannel)
        {
            std::lock_guard lk(m_whipMutex);
            if (m_whip)
            {
                m_whip->PushOpus(opusData, opusBytes, pcmFramesPerChannel);
            }
        }

        bool StartWhip(const std::string &whipUrl, int sampleRate = 48000, int channels = 1)
        {
            std::lock_guard lk(m_whipMutex);
            if (m_whip)
            {
                spdlog::info("WHIP already started");
                return true;
            }
            if (!m_cfg)
            {
                spdlog::error("StartWhip requires ConfigService");
                return false;
            }

            // certs from enrollment
            std::filesystem::path ca = "/etc/iot/keys/issuing_ca.pem";
            if (!std::filesystem::exists(ca))
            {
                ca = "/etc/iot/keys/ca_chain.pem";
            }
            std::filesystem::path crt = "/etc/iot/keys/device.crt.pem";

            WhipClient::Params p{
                .whipUrl = whipUrl, // may include ?token=..., client will normalize path and set Bearer
                .caPath = ca.string(),
                .crtPath = crt.string(),
                .sampleRate = sampleRate,
                .channels = channels};

            m_whip = std::make_unique<WhipClient>(p);
            try
            {
                m_whip->Start();
                spdlog::info("WHIP started");
                return true;
            }
            catch (const std::exception &e)
            {
                spdlog::error("WHIP start failed: {}", e.what());
                m_whip.reset();
                return false;
            }
        }

        void StopWhip()
        {
            std::lock_guard lk(m_whipMutex);
            if (m_whip)
            {
                m_whip->Stop();
                m_whip.reset();
            }
        }
    };

} // namespace snoop
