#pragma once

#include <SDL3/SDL.h>

#include <memory>     // Para shared_ptr
#include <string>     // Para string, basic_string
#include <vector>     // Para vector
class SurfaceSprite;  // lines 8-8
class Surface;        // lines 10-10
class Text;           // lines 9-9
class DeltaTimer;     // lines 11-11

// Constantes
constexpr Uint32 DEFAULT_NOTIFICATION_DURATION = 2000;
constexpr Uint32 CHEEVO_NOTIFICATION_DURATION = 4000;

// Justificado para las notificaciones
enum class NotificationText {
    LEFT,
    CENTER,
};

class Notifier {
    private:
        // Constantes
        static constexpr float ICON_SIZE = 16.0F;
        static constexpr float PADDING_OUT = 0.0F;
        static constexpr float SLIDE_SPEED = 120.0F;  // Pixels per second for slide animations

        // [SINGLETON] Objeto notifier
        static Notifier* notifier;

        enum class Status {
            RISING,
            STAY,
            VANISHING,
            FINISHED,
        };

        enum class Shape {
            ROUNDED,
            SQUARED,
        };

        struct Notification {
                std::shared_ptr<Surface> surface{nullptr};       // Superficie asociada a la notificación
                std::shared_ptr<SurfaceSprite> sprite{nullptr};  // Sprite asociado para gráficos o animaciones
                std::vector<std::string> texts;                  // Lista de textos incluidos en la notificación
                Status state{Status::RISING};                    // Estado actual de la notificación (RISING, SHOWING, etc.)
                Shape shape{Shape::SQUARED};                     // Forma de la notificación (ej. SQUARED o ROUNDED)
                SDL_FRect rect{0, 0, 0, 0};                      // Dimensiones y posición de la notificación en pantalla
                int y{0};                                        // Posición actual en el eje Y
                int travel_dist{0};                              // Distancia a recorrer (por ejemplo, en animaciones)
                std::string code;                                // Código identificador único para esta notificación
                bool can_be_removed{true};                       // Indica si la notificación puede ser eliminada
                int height{0};                                   // Altura de la notificación
                Uint32 start_time{0};                            // Momento en que se creó la notificación
                Uint32 elapsed_time{0};                          // Tiempo transcurrido desde la creación
                Uint32 display_duration{0};                      // Duración total para mostrar la notificación

                // Constructor
                explicit Notification() = default;
        };

        std::shared_ptr<Surface> icon_surface_;       // Textura para los iconos de las notificaciones
        std::shared_ptr<Text> text_;                  // Objeto para dibujar texto
        std::unique_ptr<DeltaTimer> delta_timer_;  // Timer for frame-independent animations

        // Variables
        Uint8 bg_color_;                           // Color de fondo de las notificaciones
        std::vector<Notification> notifications_;  // La lista de notificaciones activas
        bool stack_;                               // Indica si las notificaciones se apilan
        bool has_icons_;                           // Indica si el notificador tiene textura para iconos

        // Elimina las notificaciones finalizadas
        void clearFinishedNotifications();

        // Finaliza y elimnina todas las notificaciones activas
        void clearNotifications();

        // [SINGLETON] Ahora el constructor y el destructor son privados, para no poder crear objetos notifier desde fuera

        // Constructor
        Notifier(const std::string& icon_file, const std::string& text);

        // Destructor
        ~Notifier() = default;

    public:
        // [SINGLETON] Crearemos el objeto con esta función estática
        static void init(const std::string& icon_file, const std::string& text);

        // [SINGLETON] Destruiremos el objeto con esta función estática
        static void destroy();

        // [SINGLETON] Con este método obtenemos el objeto y podemos trabajar con él
        static auto get() -> Notifier*;

        // Dibuja las notificaciones por pantalla
        void render();

        // Actualiza el estado de las notificaiones
        void update(float delta_time);

        // Muestra una notificación de texto por pantalla
        void show(std::vector<std::string> texts, NotificationText text_is = NotificationText::LEFT, Uint32 display_duration = DEFAULT_NOTIFICATION_DURATION, int icon = -1, bool can_be_removed = true, const std::string& code = std::string());

        // Indica si hay notificaciones activas
        auto isActive() -> bool;

        // Obtiene los códigos de las notificaciones
        auto getCodes() -> std::vector<std::string>;
};
