#pragma once

#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>

#define MAX_ERROR_LEN 1024

#ifdef PORTAUDIO
#define HAS_PORTAUDIO true
#else
#define HAS_PORTAUDIO false
#endif

#ifdef COREAUDIO
#define HAS_COREAUDIO true
#else
#define HAS_COREAUDIO false
#endif

#ifdef COREAUDIO_TAP
#define HAS_COREAUDIO_TAP true
#else
#define HAS_COREAUDIO_TAP false
#endif

#ifdef ALSA
#define HAS_ALSA true
#else
#define HAS_ALSA false
#endif

#ifdef PULSE
#define HAS_PULSE true
#else
#define HAS_PULSE false
#endif

#ifdef PIPEWIRE
#define HAS_PIPEWIRE true
#else
#define HAS_PIPEWIRE false
#endif

#ifdef SNDIO
#define HAS_SNDIO true
#else
#define HAS_SNDIO false
#endif

#ifdef OSS
#define HAS_OSS true
#else
#define HAS_OSS false
#endif

#ifdef JACK
#define HAS_JACK true
#else
#define HAS_JACK false
#endif

#ifdef _WIN32
#define HAS_WINSCAP true
#define SDL true
#define HAS_FIFO false
#define HAS_SHMEM false
#define PATH_MAX 260
#else
#define HAS_WINSCAP false
#define HAS_FIFO true
#define HAS_SHMEM true

#endif

// These are in order of least-favourable to most-favourable choices, in case
// multiple are supported and configured.
enum input_method {
    INPUT_FIFO,
    INPUT_PORTAUDIO,
    INPUT_COREAUDIO,
    INPUT_PIPEWIRE,
    INPUT_ALSA,
    INPUT_PULSE,
    INPUT_SNDIO,
    INPUT_OSS,
    INPUT_JACK,
    INPUT_SHMEM,
    INPUT_WINSCAP,
    INPUT_MAX,
};

enum output_method {
    OUTPUT_NCURSES,
    OUTPUT_NONCURSES,
    OUTPUT_RAW,
    OUTPUT_SDL,
    OUTPUT_SDL_GLSL,
    OUTPUT_NORITAKE,
    OUTPUT_NOT_SUPORTED
};

enum mono_option { LEFT, RIGHT, AVERAGE };
enum data_format { FORMAT_ASCII = 0, FORMAT_BINARY = 1, FORMAT_NTK3000 = 2 };

enum xaxis_scale { NONE, FREQUENCY, NOTE };

enum orientation {
    ORIENT_BOTTOM,
    ORIENT_TOP,
    ORIENT_LEFT,
    ORIENT_RIGHT,
    ORIENT_SPLIT_H,
    ORIENT_SPLIT_V
};

struct config_params {
    char *color, *bcolor, *raw_target, *audio_source, **gradient_colors,
        **horizontal_gradient_colors, *data_format, *vertex_shader, *fragment_shader, *theme;

    char bar_delim, frame_delim;
    double monstercat, sens, noise_reduction, max_height, sdl_glsl_gain;

    unsigned int lower_cut_off, upper_cut_off;
    double *userEQ;
    enum input_method input;
    enum output_method output;
    enum xaxis_scale xaxis;
    enum mono_option mono_opt;
    enum orientation orientation;
    enum orientation blendDirection;
    int userEQ_keys, userEQ_enabled, col, bgcol, autobars, stereo, raw_format, ascii_range,
        bit_format, gradient, gradient_count, horizontal_gradient, horizontal_gradient_count,
        fixedbars, framerate, bar_width, bar_spacing, bar_height, autosens, overshoot, waves,
        active, remix, virtual_node, samplerate, samplebits, channels, autoconnect, sleep_timer,
        live_config, sdl_width, sdl_height, sdl_x, sdl_y, sdl_full_screen, draw_and_quit, zero_test,
        non_zero_test, reverse, sync_updates, continuous_rendering, disable_blanking,
        show_idle_bar_heads, waveform, center_align, split_stereo, left_bottom;

    // non config params, used internally
    int number_of_bars;
    int terminal_width;
    int terminal_lines;
    int is_tty;
    int terminal_remainder;
};

struct error_s {
    char message[MAX_ERROR_LEN];
    int length;
};

bool load_config(char configPath[PATH_MAX], struct config_params *p, struct error_s *error);
bool load_colors(char *themeFile, struct config_params *p, struct error_s *error);
void free_config(struct config_params *p);
bool get_themeFile(char configPath[PATH_MAX], struct config_params *p, char *cava_config_home,
                   struct error_s *error, char **themeFile);
