#pragma once

#include <SDL3/SDL.h>

#include <array>
#include <cstdint>
#include <functional>
#include <memory>
#include <string>
#include <vector>

// Alias de paleta (igual que en surface.hpp; evita incluir todo el header)
using Palette = std::array<Uint32, 256>;

class Surface;

// Modo de ordenación de paletas
enum class PaletteSortMode : std::uint8_t {
    ORIGINAL = 0,   // Paleta tal cual viene del fichero
    OPTIMAL = 1,    // Asignación óptima a la paleta por defecto (Hungarian algorithm)
    REFERENCE = 2,  // Asignación greedy a la paleta por defecto
    COUNT = 3
};

// Conversión string ↔ PaletteSortMode
auto sortModeFromString(const std::string& str) -> PaletteSortMode;
auto sortModeToString(PaletteSortMode mode) -> std::string;

class PaletteManager {
   public:
    using OnChangeCallback = std::function<void()>;

    PaletteManager(
        std::vector<std::string> raw_paths,
        const std::string& initial_name,
        PaletteSortMode initial_sort_mode,
        std::shared_ptr<Surface> game_surface,
        std::shared_ptr<Surface> border_surface,
        OnChangeCallback on_change = nullptr);

    void next();                                                      // Avanza a la siguiente paleta
    void previous();                                                  // Retrocede a la paleta anterior
    auto setByName(const std::string& name) -> bool;                  // Cambia a paleta por nombre; false si no existe
    [[nodiscard]] auto getNames() const -> std::vector<std::string>;  // Nombres disponibles (minúsculas, sin .pal)
    [[nodiscard]] auto getCurrentName() const -> std::string;         // Nombre de la paleta actual (minúsculas, sin .pal)
    [[nodiscard]] auto getPrettyName() const -> std::string;          // Nombre actual con guiones sustituidos por espacios

    void nextSortMode();                                        // Cicla al siguiente modo de ordenación
    void setSortMode(PaletteSortMode mode);                     // Establece un modo de ordenación concreto
    [[nodiscard]] auto getSortMode() const -> PaletteSortMode;  // Devuelve el modo de ordenación actual
    [[nodiscard]] auto getSortModeName() const -> std::string;  // Nombre del modo actual ("ORIGINAL", etc.)

   private:
    void apply();                                                           // Aplica la paleta actual a ambas surfaces
    [[nodiscard]] auto findIndex(const std::string& name) const -> size_t;  // Localiza paleta por nombre en el vector
    void processPathList();                                                 // Extrae nombres de archivo de las rutas completas
    static auto sortPalette(const Palette& palette, PaletteSortMode mode, const Palette& reference) -> Palette;

    std::vector<std::string> palettes_;
    Palette reference_palette_{};  // Paleta de referencia para el modo REFERENCE
    size_t current_{0};
    PaletteSortMode sort_mode_{PaletteSortMode::ORIGINAL};
    std::shared_ptr<Surface> game_surface_;
    std::shared_ptr<Surface> border_surface_;
    OnChangeCallback on_change_;
};
