// IWYU pragma: no_include <bits/std_abs.h>
#pragma once

#include <SDL3/SDL.h>  // Para Uint8, SDL_FRect, SDL_FPoint, SDL_Renderer

#include <cstdint>  // Para int32_t
#include <string>   // Para string
#include <vector>   // Para vector

// --- Constantes ---
constexpr int BLOCK = 8;
constexpr int TOTAL_DEMO_DATA = 2000;

// --- Estructuras y tipos ---
struct Overrides {
        std::string param_file;            // Fichero de parametros a utilizar
        bool clear_hi_score_table{false};  // Reinicia la tabla de records

        Overrides() = default;
};
extern Overrides overrides;

// Estructura para definir un circulo
struct Circle {
        int x, y, r;
        Circle() : x(0), y(0), r(0) {}
        Circle(int x_coord, int y_coord, int radius)
            : x(x_coord), y(y_coord), r(radius) {}
};

// Posiciones de las notificaciones
enum class NotifyPosition {
    TOP,
    BOTTOM,
    LEFT,
    MIDDLE,
    RIGHT,
};

// Estructura para datos de la demo
struct DemoKeys {
        Uint8 left;
        Uint8 right;
        Uint8 no_input;
        Uint8 fire;
        Uint8 fire_left;
        Uint8 fire_right;

        explicit DemoKeys(Uint8 l = 0, Uint8 r = 0, Uint8 ni = 0, Uint8 f = 0, Uint8 fl = 0, Uint8 fr = 0)
            : left(l), right(r), no_input(ni), fire(f), fire_left(fl), fire_right(fr) {}
};

using DemoData = std::vector<DemoKeys>;

struct Demo {
        bool enabled;                // Indica si está activo el modo demo
        bool recording;              // Indica si está activado el modo para grabar la demo
        int counter;                 // Contador para el modo demo
        DemoKeys keys;               // Variable con las pulsaciones de teclas del modo demo
        std::vector<DemoData> data;  // Vector con diferentes sets de datos con los movimientos para la demo

        Demo() : enabled(false), recording(false), counter(0) {}
        Demo(bool e, bool r, int c, const DemoKeys &k, const std::vector<DemoData> &d)
            : enabled(e), recording(r), counter(c), keys(k), data(d) {}
};

// Posiciones dentro de un rectangulo
struct Zone {
        SDL_FRect rect;         // Rectangulo que define la zona
        float center_x;         // Anclaje al 50% del eje X
        float first_quarter_x;  // Anclaje al 25% del eje X
        float third_quarter_x;  // Anclaje al 75% del eje X
        float center_y;         // Anclaje al 50% del eje Y
        float first_quarter_y;  // Anclaje al 25% del eje Y
        float third_quarter_y;  // Anclaje al 75% del eje Y
};

// --- Funciones utilitarias ---

// Colisiones y geometría
auto distanceSquared(int x1, int y1, int x2, int y2) -> double;
auto checkCollision(const Circle &a, const Circle &b) -> bool;
auto checkCollision(const Circle &a, const SDL_FRect &b) -> bool;
auto checkCollision(const SDL_FRect &a, const SDL_FRect &b) -> bool;
auto checkCollision(const SDL_FPoint &p, const SDL_FRect &r) -> bool;

// Conversión y manipulación de cadenas
auto stringToBool(const std::string &str) -> bool;
auto boolToString(bool value) -> std::string;
auto boolToOnOff(bool value) -> std::string;
auto toLower(const std::string &str) -> std::string;
auto trim(const std::string &str) -> std::string;

// Dibujo
void drawCircle(SDL_Renderer *renderer, int32_t center_x, int32_t center_y, int32_t radius);

// Funciones de suavizado (easing)
auto easeOutQuint(double time) -> double;
auto easeInQuint(double time) -> double;
auto easeInOutQuint(double time) -> double;
auto easeInQuad(double time) -> double;
auto easeOutQuad(double time) -> double;
auto easeInOutSine(double time) -> double;
auto easeInOut(double time) -> double;
auto easeInOutExpo(double time) -> double;
auto easeOutBounce(double time) -> double;
auto easeOutElastic(double time) -> double;
auto easeInElastic(double time) -> double;

// Utilidades varias
auto stringInVector(const std::vector<std::string> &vec, const std::string &str) -> bool;          // Comprueba si un vector contiene una cadena
void printWithDots(const std::string &text1, const std::string &text2, const std::string &text3);  // Imprime una línea con puntos

// Demo
auto loadDemoDataFromFile(const std::string &file_path) -> DemoData;

#ifdef RECORDING
bool saveDemoFile(const std::string &file_path, const DemoData &dd);
#endif

// Ficheros y rutas
auto getFileName(const std::string &path) -> std::string;   // Obtiene el nombre de un fichero a partir de una ruta
auto getPath(const std::string &full_path) -> std::string;  // Obtiene la ruta eliminando el nombre del fichero