#include "../../internal-include/CD/cd_internal.hpp"
#include "../../internal-include/CD/cd_types.hpp"
#include <PSX/Audio/CDXA.hpp>

namespace JabyEngine {
    namespace CDXA {
        namespace CD = JabyEngine::CD::internal;

        static struct {
            CD::BCDTimeStamp start_loc;
            CD::BCDTimeStamp last_loc;
            bool             double_speed;
            uint8_t          channel;
        } setting;

        CD::State interrupt_handler(uint8_t irq) {
            switch(irq) {
                case CD_IO::Interrupt::DataReady: {
                    // The IRQ stack is 0x1000 bytes large so this should fit
                    const auto xa_file = CD::copy_from_sector<CD::RawXADataSector>();
                    if(setting.channel == xa_file.sub_header.channel_number) {
                        CD::set_loc(setting.start_loc);
                        CD::Command::send_no_wait(CD_IO::Command::ReadS);
                    }
                } break;

                case CD_IO::Interrupt::DiskError:
                    return CD::State::Error;
            };
            return CD::State::XAMode;
        }

        void play(const volatile AutoLBAEntry* lba, uint8_t rel_lba_idx, uint8_t channel, bool double_speed) {
            setting.start_loc          = CD::BCDTimeStamp::from(lba[rel_lba_idx].get_lba());
            setting.double_speed       = double_speed;

            CD::enable_CDXA(double_speed); //< Activates PortIndex0
            set_channel(channel);
            CD::Command::send(CD_IO::Command::SetLoc, setting.start_loc.min, setting.start_loc.sec, setting.start_loc.sector);
            CD::Command::send(CD_IO::Command::ReadS);
        }

        void stop() {
            CD::pause();
        }

        void set_channel(uint8_t channel) {
            static constexpr uint8_t File = 1;

            CD::Command::send(CD_IO::Command::Filter, File, channel);
            setting.channel = channel;
        }

        void push_play() {
            stop();
            setting.last_loc  = CD::get_loc();
            CD::current_state = CD::State::Ready;
        }

        void pop_play() {
            CD::enable_CDXA(setting.double_speed); //< Activates PortIndex0

            set_channel(setting.channel);
            CD::Command::send(CD_IO::Command::SetLoc, setting.last_loc.min, setting.last_loc.sec, setting.last_loc.sector);
            CD::Command::send(CD_IO::Command::ReadS);
        }
    }
}