#pragma once

#include <SDL3/SDL.h>

#include <cstdint>
#include <deque>       // Para deque (historial)
#include <functional>  // Para function
#include <memory>      // Para shared_ptr
#include <string>      // Para string
#include <vector>      // Para vector

#include "game/ui/console_commands.hpp"  // Para CommandRegistry

class Surface;
class Sprite;
class Text;

class Console {
   public:
    // Singleton
    static void init(const std::string& font_name);
    static void destroy();
    static auto get() -> Console*;

    // Métodos principales
    void update(float delta_time);
    void render();
    void toggle();
    void handleEvent(const SDL_Event& event);

    // Constantes públicas
    static constexpr int TEXT_SIZE = 6;    // Tamaño de carácter del font de la consola
    static constexpr int LINE_HEIGHT = 7;  // TEXT_SIZE + 1px de interlineado

    // Consultas
    auto isActive() -> bool;         // true si RISING, ACTIVE o VANISHING
    auto getVisibleHeight() -> int;  // Píxeles visibles actuales (0 = oculta, height_ = totalmente visible)
    [[nodiscard]] auto getText() const -> std::shared_ptr<Text> { return text_; }

    // Prompt configurable (por defecto "> ")
    void setPrompt(const std::string& prompt) { prompt_ = prompt; }

    // Scope de comandos (filtra help y tab completion)
    void setScope(const std::string& scope);
    [[nodiscard]] auto getScope() const -> std::string;

    // Callback llamado al abrir (true) o cerrar (false) la consola
    std::function<void(bool)> on_toggle;

   private:
    enum class Status : std::uint8_t {
        HIDDEN,
        RISING,
        ACTIVE,
        VANISHING,
    };

    // Constantes visuales
    static constexpr float ANIM_DURATION = 0.3F;  // Duración de cualquier animación (segundos)

    // Constantes de consola
    static constexpr std::string_view CONSOLE_NAME = "Projecte 2026 Console";
    static constexpr std::string_view CONSOLE_VERSION = "v2.4";
    static constexpr int MAX_LINE_CHARS = 32;
    static constexpr int MAX_HISTORY_SIZE = 20;
    static constexpr float CURSOR_ON_TIME = 0.5F;
    static constexpr float CURSOR_OFF_TIME = 0.3F;
    static constexpr float TYPEWRITER_CHAR_DELAY = 0.008F;  // segundos entre letra y letra

    // [SINGLETON]
    static Console* console;

    // Constructor y destructor privados [SINGLETON]
    explicit Console(const std::string& font_name);
    ~Console() = default;

    // Métodos privados
    void buildSurface();                                                                     // Crea la Surface con el aspecto visual
    void redrawText();                                                                       // Redibuja el texto dinámico (msg + input + cursor)
    void processCommand();                                                                   // Procesa el comando introducido por el usuario
    [[nodiscard]] auto wrapText(const std::string& text) const -> std::vector<std::string>;  // Word-wrap por ancho en píxeles
    void updateCursorBlink(float delta_time);                                                // Parpadeig del cursor (només quan ACTIVE)
    void updateTypewriter(float delta_time);                                                 // Revelat lletra a lletra de msg_lines_
    void updateResizeAnimation(float delta_time);                                            // Animació d'altura quan msg_lines_ canvia
    void updateOpenCloseAnimation(float delta_time);                                         // Animació RISING/VANISHING
    void handleTextInput(const SDL_Event& event);                                            // Insereix caràcters imprimibles a input_line_
    void handleHistoryUp();                                                                  // Navega enrere a l'historial
    void handleHistoryDown();                                                                // Navega cap al present a l'historial
    void handleTab();                                                                        // Autocompletat per TAB: calcula candidats si cal i cicla

    // Objetos de renderizado
    std::shared_ptr<Text> text_;
    std::shared_ptr<Surface> surface_;
    std::shared_ptr<Sprite> sprite_;

    // Estado de la animación
    Status status_{Status::HIDDEN};
    float y_{0.0F};       // Posición Y actual (animada)
    float height_{0.0F};  // Altura del panel

    // Estado de la entrada de texto
    std::vector<std::string> msg_lines_;  // Líneas de mensaje (1 o más)
    std::string input_line_;
    std::string prompt_{"> "};  // Prompt configurable
    float cursor_timer_{0.0F};
    bool cursor_visible_{true};

    // Efecto typewriter
    int typewriter_chars_{0};  // Caracteres de msg_lines_ actualmente visibles
    float typewriter_timer_{0.0F};

    // Animación basada en tiempo (0→1 en ANIM_DURATION)
    float anim_progress_{0.0F};  // Progreso normalizado [0, 1]
    float anim_start_{0.0F};     // Valor inicial (y_ o height_)
    float anim_end_{0.0F};       // Valor final

    // Animación de altura dinámica
    float target_height_{0.0F};       // Altura objetivo (según número de líneas de mensaje)
    int notifier_offset_applied_{0};  // Acumulador del offset enviado al Notifier

    // Historial de comandos (navegable con flechas arriba/abajo)
    std::deque<std::string> history_;
    int history_index_{-1};    // -1 = en la entrada actual (presente)
    std::string saved_input_;  // guarda input_line_ al empezar a navegar

    // Estado de autocompletado (TAB)
    std::vector<std::string> tab_matches_;  // Comandos que coinciden con el prefijo actual
    int tab_index_{-1};                     // Índice actual en tab_matches_

    // Registro de comandos (metadatos YAML + handlers C++)
    CommandRegistry registry_;
};
