/*
    * Audio.hpp
    * Audio syscall implementations
    * Routes audio through the software mixer to the active hardware backend
    * (Intel HDA or Bluetooth A2DP).
    * Copyright (c) 2026 Daniel Hammer
*/

#pragma once
#include <cstdint>
#include <Drivers/Audio/IntelHda.hpp>
#include <Drivers/Audio/Mixer.hpp>
#include <Terminal/Terminal.hpp>
#include <Drivers/USB/Bluetooth/Bluetooth.hpp>
#include <Drivers/USB/Bluetooth/A2dp.hpp>
#include <Sched/Scheduler.hpp>

#include "Syscall.hpp"

namespace montauk::abi {

    // Audio handle convention:
    //   0x00 - 0x07 : Mixer virtual streams (one per opened audio handle)
    //   0x100       : Bluetooth A2DP audio output (bypasses mixer for now)

    static constexpr int AUDIO_HANDLE_BT = 0x100;

    static int64_t Sys_AudioOpen(uint32_t sampleRate, uint8_t channels, uint8_t bitsPerSample) {
        // Auto-switch: when a Bluetooth A2DP sink is connected and its stream is
        // set up (StartSource left it Configured/Open), route audio to the
        // headphones -- like a phone does when you plug in BT.  Falls back to
        // the built-in speakers (HDA) when no BT sink is ready.
        if (Drivers::USB::Bluetooth::IsInitialized()) {
            auto state = Drivers::USB::Bluetooth::A2dp::GetState();
            if (state == Drivers::USB::Bluetooth::A2dp::State::Open ||
                state == Drivers::USB::Bluetooth::A2dp::State::Streaming ||
                state == Drivers::USB::Bluetooth::A2dp::State::Configured) {
                Drivers::USB::Bluetooth::A2dp::ConfigureStream(sampleRate, channels, bitsPerSample);
                if (Drivers::USB::Bluetooth::A2dp::StartStream()) {
                    return AUDIO_HANDLE_BT;
                }
                // Stream would not start (sink unresponsive / state desync):
                // returning the BT handle anyway would make every write fail
                // with the app stuck reporting "playing" at 0:00.  Fall through
                // to the speakers instead.
                Kt::KernelLogStream(Kt::WARNING, "Audio")
                    << "BT A2DP stream failed to start; falling back to HDA";
            }
        }

        // HDA-backed mixer is the default output. The mixer keeps the HDA
        // hardware stream open across virtual streams, so multiple apps can
        // play simultaneously.
        if (Drivers::Audio::IntelHda::IsInitialized()) {
            auto* proc = Sched::GetCurrentProcessPtr();
            int pid = proc ? proc->pid : -1;
            const char* name = proc ? proc->name : "?";
            return (int64_t)Drivers::Audio::Mixer::Open(sampleRate, channels,
                                                       bitsPerSample, pid, name);
        }

        return -1;
    }

    static int64_t Sys_AudioClose(int handle) {
        if (handle == AUDIO_HANDLE_BT) {
            Drivers::USB::Bluetooth::A2dp::StopStream(true);   // drop queued tail
            return 0;
        }
        Drivers::Audio::Mixer::Close(handle);
        return 0;
    }

    static int64_t Sys_AudioWrite(int handle, const uint8_t* data, uint32_t size) {
        if (handle == AUDIO_HANDLE_BT) {
            return (int64_t)Drivers::USB::Bluetooth::A2dp::WriteAudio(data, size);
        }
        return (int64_t)Drivers::Audio::Mixer::Write(handle, data, size);
    }

    static int64_t Sys_AudioCtl(int handle, int cmd, int value) {
        if (handle == AUDIO_HANDLE_BT) {
            switch (cmd) {
                case AUDIO_CTL_SET_VOLUME:
                    Drivers::USB::Bluetooth::A2dp::SetVolume(value);
                    return 0;
                case AUDIO_CTL_GET_VOLUME:
                    return Drivers::USB::Bluetooth::A2dp::GetVolume();
                case AUDIO_CTL_PAUSE:
                    // Pause keeps the queued PCM so resume continues gaplessly.
                    if (value) Drivers::USB::Bluetooth::A2dp::StopStream(false);
                    else Drivers::USB::Bluetooth::A2dp::StartStream();
                    return 0;
                case AUDIO_CTL_GET_OUTPUT:
                    return 1;  // Bluetooth
                default:
                    return -1;
            }
        }

        if (cmd == AUDIO_CTL_GET_OUTPUT) return 0;  // HDA
        if (cmd == AUDIO_CTL_BT_STATUS) {
            if (!Drivers::USB::Bluetooth::IsInitialized()) return 0;
            return (int64_t)Drivers::USB::Bluetooth::A2dp::GetState();
        }

        return (int64_t)Drivers::Audio::Mixer::Control(handle, cmd, value);
    }

    static int64_t Sys_AudioList(AudioStreamInfo* buf, int maxCount) {
        return (int64_t)Drivers::Audio::Mixer::List(buf, maxCount);
    }

    static int64_t Sys_AudioWait(uint64_t prevSerial, uint64_t timeoutMs) {
        return (int64_t)Drivers::Audio::Mixer::Wait(prevSerial, timeoutMs);
    }

};
