#pragma once

#include <SDL3/SDL_rect.h>   // Para SDL_FRect
#include <SDL3/SDL_stdinc.h> // Para Uint32
#include <SDL3/SDL_timer.h>  // Para SDL_GetTicks
#include <stdlib.h>          // Para rand
#include <memory>            // Para unique_ptr
#include "animated_sprite.h" // Para AnimatedSprite

// --- Enumeraciones para dirección y estado ---
enum class TabeDirection : int
{
    TO_THE_LEFT = 0,
    TO_THE_RIGHT = 1,
};

enum class TabeState : int
{
    FLY = 0,
    HIT = 1,
};

// --- Estructura para el temporizador del Tabe ---
struct TabeTimer
{
    Uint32 time_until_next_spawn; // Tiempo restante para la próxima aparición
    Uint32 min_spawn_time;        // Tiempo mínimo entre apariciones
    Uint32 max_spawn_time;        // Tiempo máximo entre apariciones
    Uint32 current_time;          // Tiempo actual
    Uint32 delta_time;            // Diferencia de tiempo desde la última actualización
    Uint32 last_time;             // Tiempo de la última actualización

    // Constructor
    TabeTimer(float minTime, float maxTime)
        : min_spawn_time(minTime * 60000), max_spawn_time(maxTime * 60000),
          current_time(SDL_GetTicks())
    {
        reset();
    }

    // Restablece el temporizador con un nuevo tiempo hasta la próxima aparición
    void reset()
    {
        Uint32 range = max_spawn_time - min_spawn_time;
        time_until_next_spawn = min_spawn_time + rand() % (range + 1);
        last_time = SDL_GetTicks();
    }

    // Actualiza el temporizador, decrementando el tiempo hasta la próxima aparición
    void update()
    {
        current_time = SDL_GetTicks();
        delta_time = current_time - last_time;
        last_time = current_time;

        if (time_until_next_spawn > delta_time)
        {
            time_until_next_spawn -= delta_time;
        }
        else
        {
            time_until_next_spawn = 0;
        }
    }

    // Indica si el temporizador ha finalizado
    bool should_spawn() const
    {
        return time_until_next_spawn == 0;
    }
};

// --- Clase Tabe ---
class Tabe
{
public:
    // --- Constructores y destructor ---
    Tabe();
    ~Tabe() = default;

    // --- Métodos principales ---
    void update();                  // Actualiza la lógica
    void render();                  // Dibuja el objeto
    void enable();                  // Habilita el objeto
    void setState(TabeState state); // Establece el estado
    bool tryToGetBonus();           // Intenta obtener el bonus

    // --- Getters ---
    SDL_FRect &getCollider() { return sprite_->getRect(); } // Obtiene el área de colisión
    bool isEnabled() const { return enabled_; }             // Indica si el objeto está activo

private:
    // --- Constantes ---
    static constexpr int WIDTH_ = 32;
    static constexpr int HEIGHT_ = 32;

    // --- Objetos y punteros ---
    std::unique_ptr<AnimatedSprite> sprite_; // Sprite con los gráficos y animaciones

    // --- Variables de estado ---
    float x_ = 0;                                          // Posición X
    float y_ = 0;                                          // Posición Y
    float speed_ = 0.0f;                                   // Velocidad de movimiento
    float accel_ = 0.0f;                                   // Aceleración
    int fly_distance_ = 0;                                 // Distancia de vuelo
    int waiting_counter_ = 0;                              // Tiempo que pasa quieto
    bool enabled_ = false;                                 // Indica si el objeto está activo
    TabeDirection direction_ = TabeDirection::TO_THE_LEFT; // Dirección actual
    TabeDirection destiny_ = TabeDirection::TO_THE_LEFT;   // Destino
    TabeState state_ = TabeState::FLY;                     // Estado actual
    int hit_counter_ = 0;                                  // Contador para el estado HIT
    int number_of_hits_ = 0;                               // Cantidad de disparos recibidos
    bool has_bonus_ = true;                                // Indica si aún tiene el bonus para soltar
    TabeTimer timer_;                                      // Temporizador para gestionar la aparición

    // --- Métodos internos ---
    void move();                                                // Mueve el objeto
    void shiftSprite() { sprite_->setPos(x_, y_); }             // Actualiza la posición del sprite
    void setRandomFlyPath(TabeDirection direction, int lenght); // Establece un vuelo aleatorio
    void updateState();                                         // Actualiza el estado
    void updateTimer();                                         // Actualiza el temporizador
    void disable();                                             // Deshabilita el objeto
};