// DragonX Wallet - ImGui Edition
// Copyright 2024-2026 The Hush Developers
// Released under the GPLv3

#include "theme_loader.h"
#include "schema/color_var_resolver.h"

#include <cmath>
#include <cstdio>

namespace dragonx {
namespace ui {

// ============================================================================
// Color Parsing
// ============================================================================

bool ThemeLoader::parseHexColor(const std::string& hexStr, ImU32& outColor)
{
    if (hexStr.empty()) return false;
    
    std::string hex = hexStr;
    
    // Remove leading # or 0x
    if (hex[0] == '#') {
        hex = hex.substr(1);
    } else if (hex.size() > 2 && hex[0] == '0' && (hex[1] == 'x' || hex[1] == 'X')) {
        hex = hex.substr(2);
    }
    
    // Validate length (6 for RGB, 8 for RGBA)
    if (hex.size() != 6 && hex.size() != 8) {
        return false;
    }
    
    // Validate hex characters
    for (char c : hex) {
        if (!std::isxdigit(static_cast<unsigned char>(c))) {
            return false;
        }
    }
    
    // Parse hex value
    unsigned long value = std::strtoul(hex.c_str(), nullptr, 16);
    
    if (hex.size() == 6) {
        // RGB format: 0xRRGGBB -> IM_COL32(R, G, B, 255)
        uint8_t r = (value >> 16) & 0xFF;
        uint8_t g = (value >> 8) & 0xFF;
        uint8_t b = value & 0xFF;
        outColor = IM_COL32(r, g, b, 255);
    } else {
        // RGBA format: 0xRRGGBBAA -> IM_COL32(R, G, B, A)
        uint8_t r = (value >> 24) & 0xFF;
        uint8_t g = (value >> 16) & 0xFF;
        uint8_t b = (value >> 8) & 0xFF;
        uint8_t a = value & 0xFF;
        outColor = IM_COL32(r, g, b, a);
    }
    
    return true;
}

std::string ThemeLoader::colorToHexString(ImU32 color, bool includeAlpha)
{
    uint8_t r = (color >> IM_COL32_R_SHIFT) & 0xFF;
    uint8_t g = (color >> IM_COL32_G_SHIFT) & 0xFF;
    uint8_t b = (color >> IM_COL32_B_SHIFT) & 0xFF;
    uint8_t a = (color >> IM_COL32_A_SHIFT) & 0xFF;
    
    char buf[16];
    if (includeAlpha || a != 255) {
        snprintf(buf, sizeof(buf), "0x%02X%02X%02X%02X", r, g, b, a);
    } else {
        snprintf(buf, sizeof(buf), "0x%02X%02X%02X", r, g, b);
    }
    return std::string(buf);
}

// ============================================================================
// Multi-format Color Parsing
// ============================================================================

bool ThemeLoader::parseColorString(const std::string& str, ImU32& outColor)
{
    if (str.empty()) return false;

    // Try #hex / 0xhex first (handles both formats)
    if (parseHexColor(str, outColor)) return true;

    // Try rgba(r,g,b,a)
    if (schema::ColorVarResolver::parseRgba(str, outColor)) return true;

    // "transparent"
    if (str == "transparent") {
        outColor = IM_COL32(0, 0, 0, 0);
        return true;
    }

    return false;
}

// ============================================================================
// Luminance Calculation
// ============================================================================

float ThemeLoader::getLuminance(ImU32 color)
{
    // Extract RGB components (0-255)
    float r = ((color >> IM_COL32_R_SHIFT) & 0xFF) / 255.0f;
    float g = ((color >> IM_COL32_G_SHIFT) & 0xFF) / 255.0f;
    float b = ((color >> IM_COL32_B_SHIFT) & 0xFF) / 255.0f;
    
    // Convert to linear RGB (sRGB gamma correction)
    auto linearize = [](float c) {
        return c <= 0.03928f ? c / 12.92f : std::pow((c + 0.055f) / 1.055f, 2.4f);
    };
    
    r = linearize(r);
    g = linearize(g);
    b = linearize(b);
    
    // Calculate relative luminance (ITU-R BT.709)
    return 0.2126f * r + 0.7152f * g + 0.0722f * b;
}

// ============================================================================
// Default Color Computation
// ============================================================================

void ThemeLoader::computeDefaults(material::ColorTheme& theme, bool isDark)
{
    using namespace material;
    
    // Helper to check if a color is "unset" (black with no alpha)
    auto isUnset = [](ImU32 c) { return c == 0; };
    
    if (isDark) {
        // Dark theme defaults
        if (isUnset(theme.primaryVariant))    theme.primaryVariant = Darken(theme.primary, 0.2f);
        if (isUnset(theme.primaryLight))      theme.primaryLight = Lighten(theme.primary, 0.3f);
        
        if (isUnset(theme.secondary))         theme.secondary = Hex(0x03DAC6);
        if (isUnset(theme.secondaryVariant))  theme.secondaryVariant = Darken(theme.secondary, 0.2f);
        if (isUnset(theme.secondaryLight))    theme.secondaryLight = Lighten(theme.secondary, 0.3f);
        
        if (isUnset(theme.surface))           theme.surface = Lighten(theme.background, 0.05f);
        if (isUnset(theme.surfaceVariant))    theme.surfaceVariant = Lighten(theme.background, 0.10f);
        
        if (isUnset(theme.onPrimary))         theme.onPrimary = Hex(0xFFFFFF);
        if (isUnset(theme.onSecondary))       theme.onSecondary = Hex(0x000000);
        if (isUnset(theme.onBackground))      theme.onBackground = Hex(0xFFFFFF);
        if (isUnset(theme.onSurface))         theme.onSurface = Hex(0xFFFFFF);
        if (isUnset(theme.onSurfaceMedium))   theme.onSurfaceMedium = HexA(0xFFFFFF, 179);
        if (isUnset(theme.onSurfaceDisabled)) theme.onSurfaceDisabled = HexA(0xFFFFFF, 97);
        
        if (isUnset(theme.error))             theme.error = Hex(0xCF6679);
        if (isUnset(theme.onError))           theme.onError = Hex(0x000000);
        
        if (isUnset(theme.success))           theme.success = Hex(0x81C784);
        if (isUnset(theme.onSuccess))         theme.onSuccess = Hex(0x000000);
        if (isUnset(theme.warning))           theme.warning = Hex(0xFFB74D);
        if (isUnset(theme.onWarning))         theme.onWarning = Hex(0x000000);
        
        if (isUnset(theme.stateHover))        theme.stateHover = HexA(0xFFFFFF, 10);
        if (isUnset(theme.stateFocus))        theme.stateFocus = HexA(0xFFFFFF, 31);
        if (isUnset(theme.statePressed))      theme.statePressed = HexA(0xFFFFFF, 25);
        if (isUnset(theme.stateSelected))     theme.stateSelected = HexA(0xFFFFFF, 20);
        if (isUnset(theme.stateDragged))      theme.stateDragged = HexA(0xFFFFFF, 20);
        
        if (isUnset(theme.divider))           theme.divider = HexA(0xFFFFFF, 31);
        if (isUnset(theme.outline))           theme.outline = HexA(0xFFFFFF, 31);
        if (isUnset(theme.scrim))             theme.scrim = HexA(0x000000, 128);
    } else {
        // Light theme defaults
        if (isUnset(theme.primaryVariant))    theme.primaryVariant = Darken(theme.primary, 0.15f);
        if (isUnset(theme.primaryLight))      theme.primaryLight = Lighten(theme.primary, 0.4f);
        
        if (isUnset(theme.secondary))         theme.secondary = Hex(0x03DAC6);
        if (isUnset(theme.secondaryVariant))  theme.secondaryVariant = Darken(theme.secondary, 0.15f);
        if (isUnset(theme.secondaryLight))    theme.secondaryLight = Lighten(theme.secondary, 0.4f);
        
        if (isUnset(theme.surface))           theme.surface = Hex(0xFFFFFF);
        if (isUnset(theme.surfaceVariant))    theme.surfaceVariant = Darken(theme.background, 0.02f);
        
        if (isUnset(theme.onPrimary))         theme.onPrimary = Hex(0xFFFFFF);
        if (isUnset(theme.onSecondary))       theme.onSecondary = Hex(0x000000);
        if (isUnset(theme.onBackground))      theme.onBackground = Hex(0x000000);
        if (isUnset(theme.onSurface))         theme.onSurface = Hex(0x000000);
        if (isUnset(theme.onSurfaceMedium))   theme.onSurfaceMedium = HexA(0x000000, 179);
        if (isUnset(theme.onSurfaceDisabled)) theme.onSurfaceDisabled = HexA(0x000000, 97);
        
        if (isUnset(theme.error))             theme.error = Hex(0xB00020);
        if (isUnset(theme.onError))           theme.onError = Hex(0xFFFFFF);
        
        if (isUnset(theme.success))           theme.success = Hex(0x4CAF50);
        if (isUnset(theme.onSuccess))         theme.onSuccess = Hex(0xFFFFFF);
        if (isUnset(theme.warning))           theme.warning = Hex(0xFF9800);
        if (isUnset(theme.onWarning))         theme.onWarning = Hex(0x000000);
        
        if (isUnset(theme.stateHover))        theme.stateHover = HexA(0x000000, 10);
        if (isUnset(theme.stateFocus))        theme.stateFocus = HexA(0x000000, 31);
        if (isUnset(theme.statePressed))      theme.statePressed = HexA(0x000000, 25);
        if (isUnset(theme.stateSelected))     theme.stateSelected = HexA(0x000000, 20);
        if (isUnset(theme.stateDragged))      theme.stateDragged = HexA(0x000000, 20);
        
        if (isUnset(theme.divider))           theme.divider = HexA(0x000000, 31);
        if (isUnset(theme.outline))           theme.outline = HexA(0x000000, 31);
        if (isUnset(theme.scrim))             theme.scrim = HexA(0x000000, 128);
    }
}

// ============================================================================
// Acrylic Theme Derivation
// ============================================================================

AcrylicTheme ThemeLoader::deriveAcrylicTheme(const material::ColorTheme& theme)
{
    AcrylicTheme acrylic;
    
    // Extract primary color components for tinting
    float primaryR = ((theme.primary >> IM_COL32_R_SHIFT) & 0xFF) / 255.0f;
    float primaryG = ((theme.primary >> IM_COL32_G_SHIFT) & 0xFF) / 255.0f;
    float primaryB = ((theme.primary >> IM_COL32_B_SHIFT) & 0xFF) / 255.0f;
    
    // Extract background color components
    float bgR = ((theme.background >> IM_COL32_R_SHIFT) & 0xFF) / 255.0f;
    float bgG = ((theme.background >> IM_COL32_G_SHIFT) & 0xFF) / 255.0f;
    float bgB = ((theme.background >> IM_COL32_B_SHIFT) & 0xFF) / 255.0f;
    
    bool isDark = getLuminance(theme.background) < 0.5f;
    
    if (isDark) {
        // Dark theme: tint towards primary color
        
        // Sidebar: Strong primary tint
        acrylic.sidebar.tintColor = ImVec4(
            bgR * 0.5f + primaryR * 0.5f,
            bgG * 0.5f + primaryG * 0.5f,
            bgB * 0.5f + primaryB * 0.5f,
            1.0f
        );
        acrylic.sidebar.tintOpacity = 0.85f;
        acrylic.sidebar.luminosityOpacity = 0.4f;
        acrylic.sidebar.blurRadius = 40.0f;
        acrylic.sidebar.noiseOpacity = 0.02f;
        acrylic.sidebar.fallbackColor = ImVec4(bgR * 0.7f, bgG * 0.7f, bgB * 0.7f, 1.0f);
        acrylic.sidebar.enabled = true;
        
        // Popups: Subtle dark with slight primary tint
        acrylic.popup.tintColor = ImVec4(
            bgR * 0.8f + primaryR * 0.2f,
            bgG * 0.8f + primaryG * 0.2f,
            bgB * 0.8f + primaryB * 0.2f,
            1.0f
        );
        acrylic.popup.tintOpacity = 0.80f;
        acrylic.popup.luminosityOpacity = 0.5f;
        acrylic.popup.blurRadius = 30.0f;
        acrylic.popup.noiseOpacity = 0.02f;
        acrylic.popup.fallbackColor = ImVec4(bgR, bgG, bgB, 0.98f);
        acrylic.popup.enabled = true;
        
        // Cards: Very subtle primary tint
        acrylic.card.tintColor = ImVec4(
            bgR * 0.9f + primaryR * 0.1f,
            bgG * 0.9f + primaryG * 0.1f,
            bgB * 0.9f + primaryB * 0.1f,
            1.0f
        );
        acrylic.card.tintOpacity = 0.65f;
        acrylic.card.luminosityOpacity = 0.6f;
        acrylic.card.blurRadius = 20.0f;
        acrylic.card.noiseOpacity = 0.015f;
        acrylic.card.fallbackColor = ImVec4(bgR + 0.05f, bgG + 0.05f, bgB + 0.05f, 1.0f);
        acrylic.card.enabled = true;
        
        // Context menus: Dark and crisp
        acrylic.menu.tintColor = ImVec4(bgR, bgG, bgB, 1.0f);
        acrylic.menu.tintOpacity = 0.88f;
        acrylic.menu.luminosityOpacity = 0.45f;
        acrylic.menu.blurRadius = 25.0f;
        acrylic.menu.noiseOpacity = 0.02f;
        acrylic.menu.fallbackColor = ImVec4(bgR, bgG, bgB, 0.98f);
        acrylic.menu.enabled = true;
        
        // Tooltips: Very transparent
        acrylic.tooltip.tintColor = ImVec4(bgR, bgG, bgB, 1.0f);
        acrylic.tooltip.tintOpacity = 0.75f;
        acrylic.tooltip.luminosityOpacity = 0.5f;
        acrylic.tooltip.blurRadius = 15.0f;
        acrylic.tooltip.noiseOpacity = 0.01f;
        acrylic.tooltip.fallbackColor = ImVec4(bgR + 0.02f, bgG + 0.02f, bgB + 0.02f, 0.95f);
        acrylic.tooltip.enabled = true;
    } else {
        // Light theme
        
        // Sidebar: Light with slight primary tint
        acrylic.sidebar.tintColor = ImVec4(
            bgR * 0.9f + primaryR * 0.1f,
            bgG * 0.9f + primaryG * 0.1f,
            bgB * 0.9f + primaryB * 0.1f,
            1.0f
        );
        acrylic.sidebar.tintOpacity = 0.82f;
        acrylic.sidebar.luminosityOpacity = 0.7f;
        acrylic.sidebar.blurRadius = 30.0f;
        acrylic.sidebar.noiseOpacity = 0.015f;
        acrylic.sidebar.fallbackColor = ImVec4(bgR, bgG, bgB, 1.0f);
        acrylic.sidebar.enabled = true;
        
        // Popups
        acrylic.popup.tintColor = ImVec4(1.0f, 1.0f, 1.0f, 1.0f);
        acrylic.popup.tintOpacity = 0.85f;
        acrylic.popup.luminosityOpacity = 0.75f;
        acrylic.popup.blurRadius = 25.0f;
        acrylic.popup.noiseOpacity = 0.015f;
        acrylic.popup.fallbackColor = ImVec4(bgR, bgG, bgB, 0.98f);
        acrylic.popup.enabled = true;
        
        // Cards
        acrylic.card.tintColor = ImVec4(bgR, bgG, bgB, 1.0f);
        acrylic.card.tintOpacity = 0.70f;
        acrylic.card.luminosityOpacity = 0.75f;
        acrylic.card.blurRadius = 18.0f;
        acrylic.card.noiseOpacity = 0.01f;
        acrylic.card.fallbackColor = ImVec4(bgR, bgG, bgB, 1.0f);
        acrylic.card.enabled = true;
        
        // Menus
        acrylic.menu.tintColor = ImVec4(bgR, bgG, bgB, 1.0f);
        acrylic.menu.tintOpacity = 0.88f;
        acrylic.menu.luminosityOpacity = 0.7f;
        acrylic.menu.blurRadius = 22.0f;
        acrylic.menu.noiseOpacity = 0.015f;
        acrylic.menu.fallbackColor = ImVec4(bgR, bgG, bgB, 0.98f);
        acrylic.menu.enabled = true;
        
        // Tooltips
        acrylic.tooltip.tintColor = ImVec4(bgR - 0.02f, bgG - 0.02f, bgB - 0.02f, 1.0f);
        acrylic.tooltip.tintOpacity = 0.80f;
        acrylic.tooltip.luminosityOpacity = 0.7f;
        acrylic.tooltip.blurRadius = 12.0f;
        acrylic.tooltip.noiseOpacity = 0.01f;
        acrylic.tooltip.fallbackColor = ImVec4(bgR - 0.02f, bgG - 0.02f, bgB - 0.02f, 0.95f);
        acrylic.tooltip.enabled = true;
    }
    
    return acrylic;
}

} // namespace ui
} // namespace dragonx
