#pragma once

#include <common.h>
#include <pa_ringbuffer.h>

typedef struct {

    bool audio_enabled;
    bool ch1_left;
    bool ch1_right;
    bool ch2_left;
    bool ch2_right;
    bool ch3_left;
    bool ch3_right;
    bool ch4_left;
    bool ch4_right;

    bool ch1_dac;
    bool ch2_dac;
    bool ch4_dac;

    bool ch1_len_fz;
    bool ch2_len_fz;
    bool ch3_len_fz;
    bool ch4_len_fz;

    u8 volume_left;
    u8 volume_right;
    bool vin_left;
    bool vin_right;

    u8 sq1_duty;
    u8 sq1_volume;
    u8 sq1_sample;
    u16 sq1_period_reset;
    u16 sq1_period_timer;
    bool sq1_enable;
    bool sq1_len_enable;
    u8 sq1_sweep_pace;
    bool sq1_sweep_direction;
    u8 sq1_initial_len;
    u8 sq1_len;
    u8 sq1_initial_volume;
    bool sq1_env_direction;
    bool sq1_env_direction_buffer;
    u8 sq1_env_pace;
    u8 sq1_env_pace_buffer; 
    u8 sq1_env_timer;
    u8 sq1_sweep_step;

    u8 sq1_sweep_timer;
    bool sq1_sweep_enabled;
    u16 sq1_sweep_period;
    u16 sq1_calc_period;

    u8 sq2_duty;
    u8 sq2_volume;
    u8 sq2_sample;
    u16 sq2_period_reset;
    u16 sq2_period_timer;
    bool sq2_enable;
    bool sq2_len_enable;
    u8 sq2_initial_len;
    u8 sq2_len;
    u8 sq2_initial_volume;
    bool sq2_env_direction;
    bool sq2_env_direction_buffer;
    u8 sq2_env_pace;
    u8 sq2_env_pace_buffer;
    u8 sq2_env_timer;

    bool ch3_enable;
    bool ch3_dac;
    u8 ch3_initial_len;
    u8 ch3_len;
    u8 ch3_volume;
    u8 ch3_initial_volume;
    u16 ch3_period_timer;
    u16 ch3_period_reset;
    bool ch3_len_enable;
    u8 ch3_last_sample;
    u8 ch3_sample;

    bool ch4_enable;
    u8 ch4_initial_len;
    u8 ch4_len;
    u8 ch4_initial_volume;
    u8 ch4_volume;
    u8 ch4_env_pace;
    u8 ch4_env_pace_buffer;
    u8 ch4_env_timer;
    bool ch4_env_direction;
    bool ch4_env_direction_buffer;
    u8 ch4_clock_shift;
    bool ch4_lfsr_width;
    u8 ch4_clock_divider;
    bool ch4_len_enable;
    u16 ch4_lfsr;

    u8 wave_ram[16];

    float sq1_history[384];
    u32 sq1_index;

    float sq2_history[384];
    u32 sq2_index;

    float ch3_history[384];
    u32 ch3_index;

    float ch4_history[384];
    u32 ch4_index;

    float left_history[384];
    u32 left_index;

    float right_history[384];
    u32 right_index; 

    u64 buffer_write_index; 
    float *left_audio_buffer;
    float *right_audio_buffer;

    u32 lfsr_timer;

    float left_cap;
    float right_cap;

    int history_timer;

    double cycles_needed;

    u32 period_tick; 
    u32 ticks;

} audio_context;

typedef struct {
    audio_context ctx; 
} audio_state;

void audio_save_state(audio_state*);
void audio_load_state(const audio_state*);

void audio_init();
void audio_tick();
void audio_period_tick();
void lfsr_tick();
void audio_sample_tick();

u8 audio_read(u16 address);
void audio_write(u16 address, u8 value);

audio_context *audio_get_context();