#define _USE_MATH_DEFINES
#include "utils/color.hpp"

#include <cctype>     // Para isxdigit
#include <cmath>      // Para sinf, fmaxf, fminf, M_PI, fmodf, roundf, fmod
#include <cstdint>    // Para uint8_t
#include <stdexcept>  // Para invalid_argument
#include <string>     // Para basic_string, stoi, string

// Método estático para crear Color desde string hexadecimal
auto Color::fromHex(const std::string& hex_str) -> Color {
    std::string hex = hex_str;

    // Quitar '#' si existe
    if (!hex.empty() && hex[0] == '#') {
        hex = hex.substr(1);
    }

    // Verificar longitud válida (6 para RGB o 8 para RGBA)
    if (hex.length() != HEX_RGB_LENGTH && hex.length() != HEX_RGBA_LENGTH) {
        throw std::invalid_argument("String hexadecimal debe tener 6 o 8 caracteres");
    }

    // Verificar que todos los caracteres sean hexadecimales válidos
    for (char c : hex) {
        if (std::isxdigit(c) == 0) {
            throw std::invalid_argument("String contiene caracteres no hexadecimales");
        }
    }

    // Convertir cada par de caracteres a valores RGB(A)
    Uint8 r = static_cast<Uint8>(std::stoi(hex.substr(0, HEX_COMPONENT_LENGTH), nullptr, HEX_BASE));
    Uint8 g = static_cast<Uint8>(std::stoi(hex.substr(HEX_COMPONENT_LENGTH, HEX_COMPONENT_LENGTH), nullptr, HEX_BASE));
    Uint8 b = static_cast<Uint8>(std::stoi(hex.substr(HEX_COMPONENT_LENGTH * 2, HEX_COMPONENT_LENGTH), nullptr, HEX_BASE));
    Uint8 a = DEFAULT_ALPHA;  // Alpha por defecto

    // Si tiene 8 caracteres, extraer el alpha
    if (hex.length() == HEX_RGBA_LENGTH) {
        a = static_cast<Uint8>(std::stoi(hex.substr(HEX_COMPONENT_LENGTH * 3, HEX_COMPONENT_LENGTH), nullptr, HEX_BASE));
    }

    return Color(r, g, b, a);
}

// Implementaciones de métodos estáticos de Color
constexpr auto Color::RGB_TO_HSV(Color color) -> HSV {
    float r = color.r / 255.0F;
    float g = color.g / 255.0F;
    float b = color.b / 255.0F;

    float max = fmaxf(fmaxf(r, g), b);
    float min = fminf(fminf(r, g), b);
    float delta = max - min;

    float h = 0.0F;
    if (delta > 0.00001F) {
        if (max == r) {
            h = fmodf((g - b) / delta, 6.0F);
        } else if (max == g) {
            h = ((b - r) / delta) + 2.0F;
        } else {
            h = ((r - g) / delta) + 4.0F;
        }
        h *= 60.0F;
        if (h < 0.0F) {
            h += 360.0F;
        }
    }

    float s = (max <= 0.0F) ? 0.0F : delta / max;
    float v = max;

    return {.h = h, .s = s, .v = v};
}

constexpr auto Color::HSV_TO_RGB(HSV hsv) -> Color {
    float c = hsv.v * hsv.s;
    float x = c * (1 - std::abs(std::fmod(hsv.h / 60.0F, 2) - 1));
    float m = hsv.v - c;

    float r = 0;
    float g = 0;
    float b = 0;

    if (hsv.h < 60) {
        r = c;
        g = x;
        b = 0;
    } else if (hsv.h < 120) {
        r = x;
        g = c;
        b = 0;
    } else if (hsv.h < 180) {
        r = 0;
        g = c;
        b = x;
    } else if (hsv.h < 240) {
        r = 0;
        g = x;
        b = c;
    } else if (hsv.h < 300) {
        r = x;
        g = 0;
        b = c;
    } else {
        r = c;
        g = 0;
        b = x;
    }

    return Color(
        static_cast<uint8_t>(roundf((r + m) * 255)),
        static_cast<uint8_t>(roundf((g + m) * 255)),
        static_cast<uint8_t>(roundf((b + m) * 255)));
}

// Implementaciones del namespace Colors
namespace Colors {
    // Obtiene un color del vector de colores imitando al Coche Fantástico
    auto getColorLikeKnightRider(const std::vector<Color>& colors, int counter) -> Color {
        int cycle_length = (colors.size() * 2) - 2;
        size_t n = counter % cycle_length;

        size_t index;
        if (n < colors.size()) {
            index = n;  // Avanza: 0,1,2,3
        } else {
            index = (2 * (colors.size() - 1)) - n;  // Retrocede: 2,1
        }

        return colors[index];
    }

    auto generateMirroredCycle(Color base, ColorCycleStyle style) -> Cycle {
        Cycle result{};
        HSV base_hsv = Color::RGB_TO_HSV(base);

        for (size_t i = 0; i < CYCLE_SIZE; ++i) {
            float t = static_cast<float>(i) / (CYCLE_SIZE - 1);  // 0 → 1
            float hue_shift = 0.0F;
            float sat_shift = 0.0F;
            float val_shift = 0.0F;

            switch (style) {
                case ColorCycleStyle::SUBTLE_PULSE:
                    // Solo brillo suave
                    val_shift = 0.07F * sinf(t * M_PI);
                    break;

                case ColorCycleStyle::HUE_WAVE:
                    // Oscilación leve de tono
                    hue_shift = 15.0F * (t - 0.5F) * 2.0F;
                    val_shift = 0.05F * sinf(t * M_PI);
                    break;

                case ColorCycleStyle::VIBRANT:
                    // Cambios fuertes en tono y brillo
                    hue_shift = 35.0F * sinf(t * M_PI);
                    val_shift = 0.2F * sinf(t * M_PI);
                    sat_shift = -0.2F * sinf(t * M_PI);
                    break;

                case ColorCycleStyle::DARKEN_GLOW:
                    // Se oscurece al centro
                    val_shift = -0.15F * sinf(t * M_PI);
                    break;

                case ColorCycleStyle::LIGHT_FLASH:
                    // Se ilumina al centro
                    val_shift = 0.25F * sinf(t * M_PI);
                    break;
            }

            HSV adjusted = {
                .h = fmodf(base_hsv.h + hue_shift + 360.0F, 360.0F),
                .s = fminf(1.0F, fmaxf(0.0F, base_hsv.s + sat_shift)),
                .v = fminf(1.0F, fmaxf(0.0F, base_hsv.v + val_shift))};

            Color c = Color::HSV_TO_RGB(adjusted);
            result[i] = c;
            result[(2 * CYCLE_SIZE) - 1 - i] = c;  // espejo
        }

        return result;
    }
}  // namespace Colors