#pragma once

#include <SDL3/SDL.h>  // Para SDL_FRect, SDL_Renderer

#include <memory>  // Para shared_ptr
#include <string>  // Para basic_string, string
#include <vector>  // Para vector

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

class Sprite;
class Text;
class Texture;

// --- Clase Notifier: gestiona las notificaciones en pantalla (singleton) ---
class Notifier {
   public:
    // --- Enums ---
    enum class Position {
        TOP,     // Parte superior
        BOTTOM,  // Parte inferior
        LEFT,    // Lado izquierdo
        MIDDLE,  // Centro
        RIGHT,   // Lado derecho
    };

    // --- Métodos de singleton ---
    static void init(const std::string& icon_file, std::shared_ptr<Text> text);  // Inicializa el singleton
    static void destroy();                                                       // Libera el singleton
    static auto get() -> Notifier*;                                              // Obtiene la instancia

    // --- Métodos principales ---
    void render();                  // Dibuja las notificaciones por pantalla
    void update(float delta_time);  // Actualiza el estado de las notificaciones

    // --- Gestión de notificaciones ---
    void show(std::vector<std::string> texts, int icon = -1, const std::string& code = std::string());  // Muestra una notificación de texto por pantalla
    [[nodiscard]] auto isActive() const -> bool { return !notifications_.empty(); }                     // Indica si hay notificaciones activas
    auto getCodes() -> std::vector<std::string>;                                                        // Obtiene los códigos de las notificaciones activas
    auto checkCode(const std::string& code) -> bool { return stringInVector(getCodes(), code); }        // Comprueba si hay alguna notificación con un código concreto

   private:
    // --- Constantes de tiempo (en segundos) ---
    static constexpr float STAY_DURATION_S = 2.5F;            // Tiempo que se ve la notificación (150 frames @ 60fps)
    static constexpr float ANIMATION_SPEED_PX_PER_S = 60.0F;  // Velocidad de animación (1 pixel/frame @ 60fps)

    // --- Enums privados ---
    enum class State {
        RISING,     // Apareciendo
        STAY,       // Visible
        VANISHING,  // Desapareciendo
        FINISHED,   // Terminada
    };

    enum class Shape {
        ROUNDED,  // Forma redondeada
        SQUARED,  // Forma cuadrada
    };

    // --- Estructuras privadas ---
    struct Notification {
        std::shared_ptr<Texture> texture;  // Textura de la notificación
        std::shared_ptr<Sprite> sprite;    // Sprite asociado
        std::vector<std::string> texts;    // Textos a mostrar
        SDL_FRect rect;                    // Rectángulo de la notificación
        std::string code;                  // Código identificador de la notificación
        State state{State::RISING};        // Estado de la notificación
        Shape shape{Shape::SQUARED};       // Forma de la notificación
        float timer{0.0F};                 // Timer en segundos
        int y{0};                          // Posición vertical
        int travel_dist{0};                // Distancia a recorrer

        // Constructor
        explicit Notification()
            : texture(nullptr),
              sprite(nullptr),
              rect{.x = 0, .y = 0, .w = 0, .h = 0} {}
    };

    // --- Objetos y punteros ---
    SDL_Renderer* renderer_;                 // El renderizador de la ventana
    std::shared_ptr<Texture> icon_texture_;  // Textura para los iconos de las notificaciones
    std::shared_ptr<Text> text_;             // Objeto para dibujar texto

    // --- Variables de estado ---
    std::vector<Notification> notifications_;  // Lista de notificaciones activas
    Color bg_color_;                           // Color de fondo de las notificaciones
    // Nota: wait_time_ eliminado, ahora se usa STAY_DURATION_S
    bool stack_;      // Indica si las notificaciones se apilan
    bool has_icons_;  // Indica si el notificador tiene textura para iconos

    // --- Métodos internos ---
    void clearFinishedNotifications();                                                         // Elimina las notificaciones cuyo estado es FINISHED
    void clearAllNotifications();                                                              // Elimina todas las notificaciones activas, sin importar el estado
    [[nodiscard]] auto shouldProcessNotification(int index) const -> bool;                     // Determina si una notificación debe ser procesada (según su estado y posición)
    void processNotification(int index, float delta_time);                                     // Procesa una notificación en la posición dada: actualiza su estado y comportamiento visual
    static void playNotificationSoundIfNeeded(const Notification& notification);               // Reproduce sonido asociado si es necesario (dependiendo del estado o contenido)
    void updateNotificationState(int index, float delta_time);                                 // Actualiza el estado interno de una notificación (ej. de RISING a STAY)
    void handleRisingState(int index, float delta_time);                                       // Lógica de animación para el estado RISING (apareciendo)
    void handleStayState(int index);                                                           // Lógica para mantener una notificación visible en el estado STAY
    void handleVanishingState(int index, float delta_time);                                    // Lógica de animación para el estado VANISHING (desapareciendo)
    static void moveNotificationVertically(Notification& notification, float pixels_to_move);  // Mueve verticalmente una notificación con la cantidad de pixels especificada
    void transitionToStayState(int index);                                                     // Cambia el estado de una notificación de RISING a STAY cuando ha alcanzado su posición final

    // --- Constructores y destructor privados (singleton) ---
    Notifier(const std::string& icon_file, std::shared_ptr<Text> text);  // Constructor privado
    ~Notifier() = default;                                               // Destructor privado

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