#pragma once

#include <SDL3/SDL.h>  // Para SDL_FPoint, SDL_GetTicks, SDL_FRect, SDL_Texture, SDL_Renderer, Uint64

#include <array>    // Para array
#include <cstddef>  // Para size_t
#include <memory>   // Para shared_ptr, unique_ptr
#include <string>   // Para string, basic_string
#include <vector>   // Para vector

// Forward declarations
class EnterName;

#include "utils/color.hpp"  // Para Color

class Sprite;
class Text;
class Texture;

// --- Clase Scoreboard ---
class Scoreboard {
   public:
    // --- Enums ---
    enum class Id : size_t {
        LEFT = 0,
        CENTER = 1,
        RIGHT = 2,
        SIZE = 3
    };

    enum class Mode : int {
        SCORE,
        STAGE_INFO,
        CONTINUE,
        WAITING,
        GAME_OVER,
        DEMO,
        SCORE_TO_ENTER_NAME,  // Transición animada: SCORE → ENTER_NAME
        ENTER_NAME,
        ENTER_TO_SHOW_NAME,  // Transición animada: ENTER_NAME → SHOW_NAME
        SHOW_NAME,
        GAME_COMPLETED,
        NUM_MODES,
    };

    // --- Estructuras ---
    struct Panel {
        Mode mode;      // Modo en el que se encuentra el panel
        SDL_FRect pos;  // Posición donde dibujar el panel dentro del marcador
    };

    struct PanelPulse {
        bool active = false;      // Si el pulso está activo
        float elapsed_s = 0.0F;   // Tiempo transcurrido desde el inicio
        float duration_s = 0.5F;  // Duración total del pulso
    };

    // --- Métodos de singleton ---
    static void init();                // Crea el objeto Scoreboard
    static void destroy();             // Libera el objeto Scoreboard
    static auto get() -> Scoreboard*;  // Obtiene el puntero al objeto Scoreboard

    // --- Métodos principales ---
    void update(float delta_time);  // Actualiza la lógica del marcador
    void render();                  // Pinta el marcador

    // --- Setters ---
    void setColor(Color color);   // Establece el color del marcador
    void setPos(SDL_FRect rect);  // Establece la posición y tamaño del marcador
    void setContinue(Id id, int continue_counter) { continue_counter_.at(static_cast<size_t>(id)) = continue_counter; }
    void setHiScore(int hi_score) { hi_score_ = hi_score; }
    void setHiScoreName(const std::string& name) { hi_score_name_ = name; }
    void setMode(Id id, Mode mode);  // Establece el modo del panel y gestiona transiciones
    void setMult(Id id, float mult) { mult_.at(static_cast<size_t>(id)) = mult; }
    void setName(Id id, const std::string& name) { name_.at(static_cast<size_t>(id)) = name; }
    void setPower(float power) { power_ = power; }
    void setEnterName(Id id, const std::string& enter_name) { enter_name_.at(static_cast<size_t>(id)) = enter_name; }
    void setCharacterSelected(Id id, const std::string& character_selected) { character_selected_.at(static_cast<size_t>(id)) = character_selected; }
    void setCarouselAnimation(Id id, int selected_index, EnterName* enter_name_ptr);  // Configura la animación del carrusel
    void setScore(Id id, int score) { score_.at(static_cast<size_t>(id)) = score; }
    void setSelectorPos(Id id, int pos) { selector_pos_.at(static_cast<size_t>(id)) = pos; }
    void setStage(int stage) { stage_ = stage; }
    void triggerPanelPulse(Id id, float duration_s = 0.5F);  // Activa un pulso en el panel especificado

   private:
    // --- Objetos y punteros ---
    SDL_Renderer* renderer_;                             // El renderizador de la ventana
    std::shared_ptr<Texture> game_power_meter_texture_;  // Textura con el marcador de poder de la fase
    std::unique_ptr<Sprite> power_meter_sprite_;         // Sprite para el medidor de poder de la fase
    std::shared_ptr<Text> text_;                         // Fuente para el marcador del juego
    SDL_Texture* background_ = nullptr;                  // Textura para dibujar el marcador
    std::vector<SDL_Texture*> panel_texture_;            // Texturas para dibujar cada panel

    // --- Variables de estado ---
    std::array<std::string, static_cast<int>(Id::SIZE)> name_ = {};                // Nombre de cada jugador
    std::array<std::string, static_cast<int>(Id::SIZE)> enter_name_ = {};          // Nombre introducido para la tabla de records
    std::array<std::string, static_cast<int>(Id::SIZE)> character_selected_ = {};  // Caracter seleccionado
    std::array<EnterName*, static_cast<int>(Id::SIZE)> enter_name_ref_ = {};       // Referencias a EnterName para obtener character_list_
    std::array<float, static_cast<int>(Id::SIZE)> carousel_position_ = {};         // Posición actual del carrusel (índice en character_list_)
    std::array<float, static_cast<int>(Id::SIZE)> carousel_target_ = {};           // Posición objetivo del carrusel
    std::array<int, static_cast<int>(Id::SIZE)> carousel_prev_index_ = {};         // Índice previo para detectar cambios
    std::array<float, static_cast<int>(Id::SIZE)> text_slide_offset_ = {};         // Progreso de animación de deslizamiento (0.0 a 1.0)
    std::array<Panel, static_cast<int>(Id::SIZE)> panel_ = {};                     // Lista con todos los paneles del marcador
    std::array<PanelPulse, static_cast<int>(Id::SIZE)> panel_pulse_ = {};          // Estado de pulso para cada panel
    Colors::Cycle name_color_cycle_;                                               // Ciclo de colores para destacar el nombre una vez introducido
    Color animated_color_;                                                         // Color actual animado (ciclo automático cada 100ms)
    std::string hi_score_name_;                                                    // Nombre del jugador con la máxima puntuación
    SDL_FRect rect_ = {.x = 0, .y = 0, .w = 320, .h = 40};                         // Posición y dimensiones del marcador
    Color color_;                                                                  // Color del marcador
    std::array<size_t, static_cast<int>(Id::SIZE)> selector_pos_ = {};             // Posición del selector de letra para introducir el nombre
    std::array<int, static_cast<int>(Id::SIZE)> score_ = {};                       // Puntuación de los jugadores
    std::array<int, static_cast<int>(Id::SIZE)> continue_counter_ = {};            // Tiempo para continuar de los jugadores
    std::array<float, static_cast<int>(Id::SIZE)> mult_ = {};                      // Multiplicador de los jugadores
    Uint64 ticks_ = SDL_GetTicks();                                                // Variable donde almacenar el valor de SDL_GetTicks()
    int stage_ = 1;                                                                // Número de fase actual
    int hi_score_ = 0;                                                             // Máxima puntuación
    int time_counter_ = 0;                                                         // Contador de segundos
    Uint32 name_color_index_ = 0;                                                  // Índice actual del color en el ciclo de animación del nombre
    Uint64 name_color_last_update_ = 0;                                            // Último tick de actualización del color del nombre
    float power_ = 0.0F;                                                           // Poder actual de la fase
    std::array<float, static_cast<size_t>(Id::SIZE)> carousel_speed_scale_ = {1.0F, 1.0F, 1.0F};

    // --- Constantes ---
    static constexpr int CAROUSEL_VISIBLE_LETTERS = 9;
    static constexpr float TEXT_SLIDE_DURATION = 0.3F;     // Duración de la animación de deslizamiento en segundos
    static constexpr int PANEL_PULSE_LIGHTEN_AMOUNT = 40;  // Cantidad de aclarado para el pulso del panel

    // --- Variables de aspecto ---
    Color text_color1_, text_color2_;  // Colores para los marcadores del texto;

    // --- Puntos predefinidos para colocar elementos en los paneles ---
    SDL_FPoint slot4_1_, slot4_2_, slot4_3_, slot4_4_;
    SDL_FPoint enter_name_pos_;

    // --- Métodos internos ---
    void recalculateAnchors();                            // Recalcula las anclas de los elementos
    static auto updateScoreText(int num) -> std::string;  // Transforma un valor numérico en una cadena de 7 cifras
    void createBackgroundTexture();                       // Crea la textura de fondo
    void createPanelTextures();                           // Crea las texturas de los paneles
    void fillPanelTextures();                             // Rellena los diferentes paneles del marcador
    void fillBackgroundTexture();                         // Rellena la textura de fondo
    void updateTimeCounter();                             // Actualiza el contador
    void updateNameColorIndex();                          // Actualiza el índice del color animado del nombre
    void updateCarouselAnimation(float delta_time);       // Actualiza la animación del carrusel
    void updateTextSlideAnimation(float delta_time);      // Actualiza la animación de deslizamiento de texto
    void updatePanelPulses(float delta_time);             // Actualiza las animaciones de pulso de los paneles
    void renderSeparator();                               // Dibuja la línea que separa la zona de juego del marcador
    void renderPanelContent(size_t panel_index);
    void renderScoreMode(size_t panel_index);
    void renderDemoMode();
    void renderWaitingMode();
    void renderGameOverMode();
    void renderStageInfoMode();
    void renderContinueMode(size_t panel_index);
    void renderScoreToEnterNameMode(size_t panel_index);  // Renderiza la transición SCORE → ENTER_NAME
    void renderEnterNameMode(size_t panel_index);
    void renderNameInputField(size_t panel_index);
    void renderEnterToShowNameMode(size_t panel_index);  // Renderiza la transición ENTER_NAME → SHOW_NAME
    void renderShowNameMode(size_t panel_index);
    void renderGameCompletedMode(size_t panel_index);
    void renderCarousel(size_t panel_index, int center_x, int y);  // Pinta el carrusel de caracteres con colores LERP

    // --- Constructores y destructor privados (singleton) ---
    Scoreboard();   // Constructor privado
    ~Scoreboard();  // Destructor privado

    // --- Instancia singleton ---
    static Scoreboard* instance;  // Instancia única de Scoreboard
};
