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

#pragma once

#include "imgui.h"
#include <string>
#include <map>
#include <optional>

namespace dragonx {
namespace ui {
namespace schema {

// ============================================================================
// Color properties shared by all styleable elements
// ============================================================================

struct ElementColors {
    std::string color;              // "var(--on-primary)" | "rgba(...)" | "#hex" | ""
    std::string background;
    std::string backgroundHover;    // null = auto-derive
    std::string backgroundActive;   // null = auto-derive
    std::string borderColor;
};

// ============================================================================
// Element Style Structs
// ============================================================================

/**
 * @brief Style for button elements
 *
 * Sentinel values: 0 or -1 = inherit from globals, "" = inherit
 */
struct ButtonStyle {
    float width        = 0;     // 0 = auto-size
    float height       = 0;     // 0 = auto from font + padding
    std::string font;           // "" = inherit from globals
    float padding[2]   = {0, 0}; // [h, v] — 0 = inherit
    float opacity      = -1;    // -1 = inherit, 0.0-1.0
    float borderRadius = -1;    // -1 = inherit
    float borderWidth  = -1;    // -1 = inherit
    float minWidth     = -1;    // -1 = inherit
    std::string align;          // "" | "left" | "center" | "right"
    ElementColors colors;

    // Gap between adjacent buttons (layout helper)
    float gap = 0;
};

/**
 * @brief Style for text input elements
 */
struct InputStyle {
    float width        = 0;     // 0 = auto, -1 = fill remaining
    float height       = 0;     // 0 = single-line auto
    int   lines        = 0;     // 0 = inherit, 1 = single, >1 = multiline
    std::string font;
    float padding[2]   = {0, 0};
    float borderRadius = -1;
    float borderWidth  = -1;
    ElementColors colors;
    std::string borderColorFocus;   // "var(--primary)" for focus ring
    std::string placeholderColor;

    // Ratio-based width (alternative to fixed)
    float widthRatio   = -1;    // -1 = not set, 0.0-1.0 = fraction of available
    float maxWidth     = -1;    // -1 = no limit
};

/**
 * @brief Style for text labels
 */
struct LabelStyle {
    std::string font;
    std::string color;
    float opacity      = -1;
    std::string align;
    int   truncate     = 0;     // 0 = no truncation, >0 = max chars
    float position     = -1;    // SameLine label position (-1 = not set)
};

/**
 * @brief Style for table columns
 */
struct ColumnStyle {
    float width        = -1;
    std::string font;
    std::string align;
    int   truncate     = 0;
};

/**
 * @brief Style for table elements
 */
struct TableStyle {
    float minHeight     = -1;
    float heightRatio   = -1;   // fraction of available space
    float bottomReserve = -1;
    float rowHeight     = -1;
    std::string headerFont;
    std::string cellFont;
    std::string borderColor;
    std::string stripeColor;
    std::map<std::string, ColumnStyle> columns;
};

/**
 * @brief Style for checkbox elements
 */
struct CheckboxStyle {
    std::string font;
    std::string color;
    std::string checkColor;
    std::string background;
};

/**
 * @brief Style for combo/dropdown elements
 */
struct ComboStyle {
    float width        = 0;
    std::string font;
    std::string color;
    std::string background;
    float borderRadius = -1;
    int   truncate     = 0;
};

/**
 * @brief Style for slider elements
 */
struct SliderStyle {
    float width        = 0;
    std::string trackColor;
    std::string fillColor;
    std::string thumbColor;
    float thumbRadius  = -1;
};

/**
 * @brief Style for windows and dialogs
 */
struct WindowStyle {
    float width        = 0;
    float height       = 0;
    float padding[2]   = {0, 0};
    float borderRadius = -1;
    float borderWidth  = -1;
    std::string background;
    std::string borderColor;
    std::string titleFont;
};

/**
 * @brief Style for separator lines
 */
struct SeparatorStyle {
    std::string color;
    float thickness    = -1;
    float margin[2]    = {0, 0};  // [top, bottom]
};

/**
 * @brief Style for DrawList-driven custom elements (progress rings, sparklines, etc.)
 */
struct DrawElementStyle {
    std::string color;
    std::string background;
    float thickness    = -1;
    float radius       = -1;
    float opacity      = -1;
    float size         = -1;   // generic size (e.g., QR code size)
    float height       = -1;

    // Additional named properties for flexible DrawList elements
    std::map<std::string, std::string> extraColors;
    std::map<std::string, float> extraFloats;

    /// Look up any extra float by key, returning fallback if absent.
    float getFloat(const std::string& key, float fallback = 0.0f) const {
        auto it = extraFloats.find(key);
        return it != extraFloats.end() ? it->second : fallback;
    }

    /// Return size if set (>= 0), else fallback.
    float sizeOr(float fallback) const { return size >= 0.0f ? size : fallback; }
};

/**
 * @brief Style for spacing (layout helper)
 */
struct SpacingStyle {
    float size = 0;
};

// ============================================================================
// Responsive overrides
// ============================================================================

/**
 * @brief Per-breakpoint property overrides
 *
 * Only non-sentinel values override the base style. Applied on top of
 * the element's base style when the current window size matches the
 * breakpoint.
 */
struct ResponsiveButtonOverride {
    float width        = 0;
    float height       = 0;
    std::string font;
    float padding[2]   = {0, 0};
};

struct ResponsiveInputOverride {
    float width        = 0;
    float height       = 0;
};

// ============================================================================
// Breakpoint definitions
// ============================================================================

struct BreakpointDef {
    float maxWidth  = -1;   // -1 = no constraint
    float maxHeight = -1;
    float minWidth  = -1;
    float minHeight = -1;
};

struct BreakpointConfig {
    BreakpointDef compact;
    BreakpointDef expanded;
};

// ============================================================================
// JSON parsing helpers (implemented in element_styles.cpp)
// ============================================================================

// Forward declare nlohmann::json to avoid header dependency
namespace detail {
    // Parse individual style types from a JSON object
    // These are called by UISchema during load — not for external use
    void parseButtonStyle(const void* jsonObj, ButtonStyle& out);
    void parseInputStyle(const void* jsonObj, InputStyle& out);
    void parseLabelStyle(const void* jsonObj, LabelStyle& out);
    void parseTableStyle(const void* jsonObj, TableStyle& out);
    void parseCheckboxStyle(const void* jsonObj, CheckboxStyle& out);
    void parseComboStyle(const void* jsonObj, ComboStyle& out);
    void parseSliderStyle(const void* jsonObj, SliderStyle& out);
    void parseWindowStyle(const void* jsonObj, WindowStyle& out);
    void parseSeparatorStyle(const void* jsonObj, SeparatorStyle& out);
    void parseDrawElementStyle(const void* jsonObj, DrawElementStyle& out);
    void parseBreakpointConfig(const void* jsonObj, BreakpointConfig& out);
    void parseElementColors(const void* jsonObj, ElementColors& out);
    void parseResponsiveButtonOverride(const void* jsonObj, ResponsiveButtonOverride& out);
}

// ============================================================================
// Merge helpers — apply overlay on top of base (non-sentinel values win)
// ============================================================================

void mergeButton(ButtonStyle& base, const ButtonStyle& overlay);
void mergeInput(InputStyle& base, const InputStyle& overlay);
void mergeLabel(LabelStyle& base, const LabelStyle& overlay);
void mergeWindow(WindowStyle& base, const WindowStyle& overlay);
void applyResponsiveButton(ButtonStyle& base, const ResponsiveButtonOverride& ovr);

} // namespace schema
} // namespace ui
} // namespace dragonx
