#pragma once

#include <SDL3/SDL.h>  // Para SDL_Keycode, SDL_Event, Uint64

#include <memory>       // Para shared_ptr, unique_ptr
#include <string_view>  // Para string_view
#include <vector>       // Para vector

#include "core/system/section.hpp"   // for Options, Name (ptr only)
#include "game/entities/player.hpp"  // for Player

class Fade;
class GameLogo;
class Sprite;
class Text;
class TiledBG;

namespace Options {
    struct Gamepad;
}  // namespace Options

// --- Clase Title: pantalla de título y menú principal del juego ---
//
// Esta clase gestiona la pantalla de título del juego, incluyendo el menú principal
// y la transición entre diferentes modos de juego.
//
// Funcionalidades principales:
// • Logo animado: muestra y anima el logotipo principal del juego
// • Selección de jugadores: permite iniciar partidas de 1 o 2 jugadores
// • Modo attract: cicla automáticamente entre título y demo
// • Efectos visuales: parpadeos, transiciones y efectos de fondo
// • Gestión de controles: soporte para teclado y múltiples gamepads
// • Timeouts automáticos: transición automática si no hay interacción
//
// La clase utiliza un sistema de tiempo basado en segundos para garantizar
// comportamiento consistente independientemente del framerate.
class Title {
   public:
    // --- Constructor y destructor ---
    Title();
    ~Title();

    // --- Callbacks para el bucle SDL_MAIN_USE_CALLBACKS ---
    void iterate();                            // Ejecuta un frame
    void handleEvent(const SDL_Event& event);  // Procesa un evento

    // --- Bucle principal legacy (fallback) ---
    void run();

   private:
    // --- Constantes de tiempo (en segundos) ---
    static constexpr float START_PRESSED_DELAY_S = 1666.67F / 1000.0F;  // Tiempo antes de fade tras pulsar start (100 frames a 60fps)
    static constexpr int MUSIC_FADE_OUT_LONG_MS = 1500;                 // Fade out largo de música
    static constexpr int MUSIC_FADE_OUT_SHORT_MS = 300;                 // Fade out corto de música

    // --- Constantes de parpadeo (en segundos) ---
    static constexpr float LOGO_BLINK_PERIOD_S = 833.0F / 1000.0F;   // Período de parpadeo del logo (833ms)
    static constexpr float LOGO_BLINK_ON_TIME_S = 583.0F / 1000.0F;  // Tiempo encendido del logo (583ms)
    static constexpr float START_BLINK_PERIOD_S = 167.0F / 1000.0F;  // Período de parpadeo del start (167ms)
    static constexpr float START_BLINK_ON_TIME_S = 83.0F / 1000.0F;  // Tiempo encendido del start (83ms)

    // --- Constantes de layout ---
    static constexpr int MINI_LOGO_Y_DIVISOR = 5;     // Divisor para posición Y del mini logo
    static constexpr int MINI_LOGO_Y_FACTOR = 4;      // Factor para posición Y del mini logo
    static constexpr int COPYRIGHT_TEXT_SPACING = 3;  // Espaciado del texto de copyright

    // --- Constantes de texto y configuración ---
    static constexpr std::string_view TEXT_COPYRIGHT = "@2020,2025 JailDesigner";  // Texto de copyright
    static constexpr bool ALLOW_TITLE_ANIMATION_SKIP = false;                      // Permite saltar la animación del título

    // --- Enums ---
    enum class State {
        LOGO_ANIMATING,          // El logo está animándose
        LOGO_FINISHED,           // El logo ha terminado de animarse
        START_HAS_BEEN_PRESSED,  // Se ha pulsado el botón de start
    };

    // --- Estructuras privadas ---
    struct Anchor {
        int mini_logo;       // Ancla del logo mini
        int copyright_text;  // Ancla del texto de copyright
    };

    // --- Objetos y punteros ---
    std::shared_ptr<Text> text_;                    // Objeto de texto para escribir en pantalla
    std::unique_ptr<Fade> fade_;                    // Fundido en pantalla
    std::unique_ptr<TiledBG> tiled_bg_;             // Fondo animado de tiles
    std::unique_ptr<GameLogo> game_logo_;           // Logo del juego
    std::unique_ptr<Sprite> mini_logo_sprite_;      // Logo JailGames mini
    std::vector<std::shared_ptr<Player>> players_;  // Vector de jugadores

    // --- Variables de estado ---
    Anchor anchor_;                                                  // Anclas para definir la posición de los elementos del título
    Section::Name next_section_;                                     // Siguiente sección a cargar
    Section::Options selection_ = Section::Options::TITLE_TIME_OUT;  // Opción elegida en el título
    State state_;                                                    // Estado actual de la sección
    Uint64 last_time_ = 0;                                           // Último timestamp para calcular delta-time
    float counter_time_ = 0.0F;                                      // Temporizador para la pantalla de título (en segundos)
    float blink_accumulator_ = 0.0F;                                 // Acumulador para el parpadeo (en segundos)
    int num_controllers_;                                            // Número de mandos conectados
    bool should_render_start_prompt_ = false;                        // Indica si se muestra el texto de PRESS START BUTTON TO PLAY
    bool player1_start_pressed_ = false;                             // Indica si se ha pulsado el botón de empezar para el jugador 1
    bool player2_start_pressed_ = false;                             // Indica si se ha pulsado el botón de empezar para el jugador 2

    // --- Ciclo de vida del título ---
    void update(float delta_time);       // Actualiza las variables del objeto
    auto calculateDeltaTime() -> float;  // Calcula el tiempo transcurrido desde el último frame
    void updateState(float delta_time);  // Actualiza el estado actual del título
    void setState(State state);          // Cambia el estado del título
    void resetCounter();                 // Reinicia el contador interno

    // --- Entrada de usuario ---
    void checkEvents();                                                                          // Comprueba los eventos
    void checkInput();                                                                           // Comprueba las entradas
    void handleKeyDownEvent(const SDL_Event& event);                                             // Maneja el evento de tecla presionada
    void processKeyboardStart();                                                                 // Procesa las entradas del teclado
    void processControllerInputs();                                                              // Procesa las entradas de los mandos
    [[nodiscard]] static auto isStartButtonPressed(const Options::Gamepad* controller) -> bool;  // Comprueba si se ha pulsado el botón Start
    void handleStartButtonPress(const Options::Gamepad* controller);                             // Maneja la pulsación del botón Start
    [[nodiscard]] auto canProcessStartButton() const -> bool;                                    // Verifica si se puede procesar la pulsación del botón Start
    void processPlayer1Start();                                                                  // Procesa el inicio del jugador 1
    void processPlayer2Start();                                                                  // Procesa el inicio del jugador 2
    void activatePlayerAndSetState(Player::Id player_id);                                        // Activa al jugador y cambia el estado del título

    // --- Gestión de jugadores ---
    void initPlayers();                                        // Inicializa los jugadores
    void updatePlayers(float delta_time);                      // Actualiza los jugadores
    void renderPlayers();                                      // Renderiza los jugadores
    auto getPlayer(Player::Id id) -> std::shared_ptr<Player>;  // Obtiene un jugador a partir de su "id"

    // --- Visualización / Renderizado ---
    void render();                             // Dibuja el objeto en pantalla
    void updateFade();                         // Actualiza el efecto de fundido (fade in/out)
    void updateStartPrompt(float delta_time);  // Actualiza el mensaje de "Pulsa Start"
    void renderStartPrompt();                  // Dibuja el mensaje de "Pulsa Start" en pantalla
    void renderCopyright();                    // Dibuja el aviso de copyright

    // --- Utilidades estáticas ---
    static void swapControllers();  // Intercambia la asignación de mandos a los jugadores
    static void swapKeyboard();     // Intercambia el teclado de jugador
    static void showControllers();  // Muestra información sobre los controles y los jugadores
};