#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

#include "color.h"  // 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,
            ENTER_NAME,
            SHOW_NAME,
            GAME_COMPLETED,
            NUM_MODES,
        };

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

        // --- 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();  // 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) { panel_.at(static_cast<size_t>(id)).mode = mode; }
        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 setRecordName(Id id, const std::string &record_name) { record_name_.at(static_cast<size_t>(id)) = record_name; }
        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; }

    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_scoreboard_;              // 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)> record_name_ = {};  // Nombre introducido para la tabla de records
        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<float, static_cast<int>(Id::SIZE)> mult_ = {};               // Multiplicador de los jugadores
        std::array<int, static_cast<int>(Id::SIZE)> continue_counter_ = {};     // Tiempo para continuar de los jugadores
        std::array<Panel, static_cast<int>(Id::SIZE)> panel_ = {};              // Lista con todos los paneles del marcador

        int stage_ = 1;                     // Número de fase actual
        int hi_score_ = 0;                  // Máxima puntuación
        float power_ = 0;                   // Poder actual de la fase
        std::string hi_score_name_;         // Nombre del jugador con la máxima puntuación
        Color color_;                       // Color del marcador
        SDL_FRect rect_ = {0, 0, 320, 40};  // Posición y dimensiones del marcador
        Uint64 ticks_ = SDL_GetTicks();     // Variable donde almacenar el valor de SDL_GetTicks()
        int time_counter_ = 0;              // Contador de segundos
        int loop_counter_ = 0;              // Contador de bucle
        std::vector<Color> name_colors_;    // Colores para destacar el nombre una vez introducido

        // --- 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 renderSeparator();                               // Dibuja la línea que separa la zona de juego del marcador
        void iniNameColors();                                 // Inicializa el vector de colores para el nombre
        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 renderEnterNameMode(size_t panel_index);
        void renderNameInputField(size_t panel_index);
        void renderShowNameMode(size_t panel_index);
        void renderGameCompletedMode(size_t panel_index);

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

        // --- Singleton ---
        static Scoreboard *instance;
};
