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

#pragma once

#include "../colors.h"
#include "../typography.h"
#include "../layout.h"
#include "../../schema/ui_schema.h"
#include "imgui.h"
#include "imgui_internal.h"

namespace dragonx {
namespace ui {
namespace material {

// ============================================================================
// Material Design Input Controls
// ============================================================================
// Based on https://m2.material.io/components/selection-controls
//
// Selection controls allow users to complete tasks that involve making choices:
// - Switch: Toggle single option on/off
// - Checkbox: Select multiple options
// - Radio: Select one option from a set

// ============================================================================
// Switch
// ============================================================================

/**
 * @brief Material Design switch (toggle)
 * 
 * @param label Text label
 * @param value Pointer to boolean value
 * @param disabled If true, switch is non-interactive
 * @return true if value changed
 */
bool Switch(const char* label, bool* value, bool disabled = false);

// ============================================================================
// Checkbox
// ============================================================================

/**
 * @brief Checkbox state
 */
enum class CheckboxState {
    Unchecked,
    Checked,
    Indeterminate  // For parent with mixed children
};

/**
 * @brief Material Design checkbox
 * 
 * @param label Text label
 * @param value Pointer to boolean value
 * @param disabled If true, checkbox is non-interactive
 * @return true if value changed
 */
bool Checkbox(const char* label, bool* value, bool disabled = false);

/**
 * @brief Tri-state checkbox
 */
bool Checkbox(const char* label, CheckboxState* state, bool disabled = false);

// ============================================================================
// Radio Button
// ============================================================================

/**
 * @brief Material Design radio button
 * 
 * @param label Text label
 * @param active true if this option is selected
 * @param disabled If true, radio is non-interactive
 * @return true if clicked (caller should update selection)
 */
bool RadioButton(const char* label, bool active, bool disabled = false);

/**
 * @brief Radio button with int selection
 * 
 * @param label Text label
 * @param selection Pointer to current selection
 * @param value Value this radio represents
 * @return true if clicked
 */
bool RadioButton(const char* label, int* selection, int value, bool disabled = false);

// ============================================================================
// Implementation
// ============================================================================

inline bool Switch(const char* label, bool* value, bool disabled) {
    ImGuiWindow* window = ImGui::GetCurrentWindow();
    if (window->SkipItems)
        return false;
    
    ImGui::PushID(label);
    
    // Switch dimensions (Material spec: 36x14 track, 20dp thumb)
    const float trackWidth = 36.0f;
    const float trackHeight = 14.0f;
    const float thumbRadius = 10.0f;  // 20dp diameter
    const float thumbTravel = trackWidth - thumbRadius * 2;
    
    // Calculate layout
    ImVec2 pos = window->DC.CursorPos;
    float labelWidth = ImGui::CalcTextSize(label).x;
    float totalWidth = trackWidth + spacing::dp(2) + labelWidth;
    float totalHeight = ImMax(trackHeight + 6.0f, size::TouchTarget);  // Min 48dp touch target
    
    ImRect bb(pos, ImVec2(pos.x + totalWidth, pos.y + totalHeight));
    
    // Interaction
    ImGuiID id = window->GetID("##switch");
    ImGui::ItemSize(bb);
    if (!ImGui::ItemAdd(bb, id))
        return false;
    
    bool hovered, held;
    bool pressed = ImGui::ButtonBehavior(bb, id, &hovered, &held) && !disabled;
    
    bool changed = false;
    if (pressed) {
        *value = !*value;
        changed = true;
    }
    
    // Animation (simple snap for now)
    float thumbX = *value ? (thumbTravel) : 0;
    
    // Draw track
    ImDrawList* drawList = window->DrawList;
    float trackY = pos.y + totalHeight * 0.5f;
    ImVec2 trackMin(pos.x, trackY - trackHeight * 0.5f);
    ImVec2 trackMax(pos.x + trackWidth, trackY + trackHeight * 0.5f);
    
    ImU32 trackColor;
    if (disabled) {
        trackColor = schema::UI().resolveColor("var(--switch-track-off)", IM_COL32(255, 255, 255, 30));
    } else if (*value) {
        trackColor = PrimaryVariant();  // Primary at 50% opacity
    } else {
        trackColor = schema::UI().resolveColor("var(--switch-track-on)", IM_COL32(255, 255, 255, 97));
    }
    
    drawList->AddRectFilled(trackMin, trackMax, trackColor, trackHeight * 0.5f);
    
    // Draw thumb
    ImVec2 thumbCenter(pos.x + thumbRadius + thumbX, trackY);
    
    ImU32 thumbColor;
    if (disabled) {
        thumbColor = schema::UI().resolveColor("var(--switch-thumb-off)", IM_COL32(189, 189, 189, 255));
    } else if (*value) {
        thumbColor = Primary();
    } else {
        thumbColor = schema::UI().resolveColor("var(--switch-thumb-on)", IM_COL32(250, 250, 250, 255));
    }
    
    // Thumb shadow
    drawList->AddCircleFilled(ImVec2(thumbCenter.x + 1, thumbCenter.y + 2), thumbRadius, schema::UI().resolveColor("var(--control-shadow)", IM_COL32(0, 0, 0, 60)));
    drawList->AddCircleFilled(thumbCenter, thumbRadius, thumbColor);
    
    // Hover ripple effect
    if (hovered && !disabled) {
        ImU32 ripple = *value ? WithAlpha(Primary(), 25) : schema::UI().resolveColor("var(--hover-overlay)", IM_COL32(255, 255, 255, 25));
        drawList->AddCircleFilled(thumbCenter, thumbRadius + 12.0f, ripple);
    }
    
    // Draw label
    ImVec2 labelPos(pos.x + trackWidth + spacing::dp(2), pos.y + (totalHeight - ImGui::GetFontSize()) * 0.5f);
    ImU32 labelColor = disabled ? OnSurfaceDisabled() : OnSurface();
    drawList->AddText(labelPos, labelColor, label);
    
    ImGui::PopID();
    
    return changed;
}

inline bool Checkbox(const char* label, bool* value, bool disabled) {
    ImGuiWindow* window = ImGui::GetCurrentWindow();
    if (window->SkipItems)
        return false;
    
    ImGui::PushID(label);
    
    // Checkbox dimensions (18dp box, 48dp touch target)
    const float boxSize = 18.0f;
    
    // Calculate layout
    ImVec2 pos = window->DC.CursorPos;
    float labelWidth = ImGui::CalcTextSize(label).x;
    float totalWidth = boxSize + spacing::dp(2) + labelWidth;
    float totalHeight = size::TouchTarget;
    
    ImRect bb(pos, ImVec2(pos.x + totalWidth, pos.y + totalHeight));
    
    // Interaction
    ImGuiID id = window->GetID("##checkbox");
    ImGui::ItemSize(bb);
    if (!ImGui::ItemAdd(bb, id))
        return false;
    
    bool hovered, held;
    bool pressed = ImGui::ButtonBehavior(bb, id, &hovered, &held) && !disabled;
    
    bool changed = false;
    if (pressed) {
        *value = !*value;
        changed = true;
    }
    
    // Draw checkbox
    ImDrawList* drawList = window->DrawList;
    float centerY = pos.y + totalHeight * 0.5f;
    ImVec2 boxMin(pos.x, centerY - boxSize * 0.5f);
    ImVec2 boxMax(pos.x + boxSize, centerY + boxSize * 0.5f);
    
    ImU32 boxColor, checkColor;
    if (disabled) {
        boxColor = OnSurfaceDisabled();
        checkColor = schema::UI().resolveColor("var(--checkbox-check)", IM_COL32(0, 0, 0, 255));
    } else if (*value) {
        boxColor = Primary();
        checkColor = OnPrimary();
    } else {
        boxColor = OnSurfaceMedium();
        checkColor = OnPrimary();
    }
    
    if (*value) {
        // Filled checkbox with checkmark
        drawList->AddRectFilled(boxMin, boxMax, boxColor, 2.0f);
        
        // Draw checkmark
        ImVec2 checkStart(boxMin.x + 4, centerY);
        ImVec2 checkMid(boxMin.x + 7, centerY + 3);
        ImVec2 checkEnd(boxMin.x + 14, centerY - 4);
        
        drawList->AddLine(checkStart, checkMid, checkColor, 2.0f);
        drawList->AddLine(checkMid, checkEnd, checkColor, 2.0f);
    } else {
        // Empty checkbox border
        drawList->AddRect(boxMin, boxMax, boxColor, 2.0f, 0, 2.0f);
    }
    
    // Hover ripple
    if (hovered && !disabled) {
        ImVec2 boxCenter((boxMin.x + boxMax.x) * 0.5f, centerY);
        drawList->AddCircleFilled(boxCenter, boxSize, 
            *value ? WithAlpha(Primary(), 25) : schema::UI().resolveColor("var(--hover-overlay)", IM_COL32(255, 255, 255, 25)));
    }
    
    // Draw label
    ImVec2 labelPos(pos.x + boxSize + spacing::dp(2), pos.y + (totalHeight - ImGui::GetFontSize()) * 0.5f);
    ImU32 labelColor = disabled ? OnSurfaceDisabled() : OnSurface();
    drawList->AddText(labelPos, labelColor, label);
    
    ImGui::PopID();
    
    return changed;
}

inline bool Checkbox(const char* label, CheckboxState* state, bool disabled) {
    bool checked = (*state == CheckboxState::Checked);
    bool indeterminate = (*state == CheckboxState::Indeterminate);
    
    ImGuiWindow* window = ImGui::GetCurrentWindow();
    if (window->SkipItems)
        return false;
    
    ImGui::PushID(label);
    
    const float boxSize = 18.0f;
    
    ImVec2 pos = window->DC.CursorPos;
    float labelWidth = ImGui::CalcTextSize(label).x;
    float totalWidth = boxSize + spacing::dp(2) + labelWidth;
    float totalHeight = size::TouchTarget;
    
    ImRect bb(pos, ImVec2(pos.x + totalWidth, pos.y + totalHeight));
    
    ImGuiID id = window->GetID("##checkbox");
    ImGui::ItemSize(bb);
    if (!ImGui::ItemAdd(bb, id))
        return false;
    
    bool hovered, held;
    bool pressed = ImGui::ButtonBehavior(bb, id, &hovered, &held) && !disabled;
    
    bool changed = false;
    if (pressed) {
        // Cycle: Unchecked -> Checked -> Unchecked (indeterminate only set programmatically)
        *state = (*state == CheckboxState::Checked) ? CheckboxState::Unchecked : CheckboxState::Checked;
        changed = true;
    }
    
    ImDrawList* drawList = window->DrawList;
    float centerY = pos.y + totalHeight * 0.5f;
    ImVec2 boxMin(pos.x, centerY - boxSize * 0.5f);
    ImVec2 boxMax(pos.x + boxSize, centerY + boxSize * 0.5f);
    
    ImU32 boxColor = disabled ? OnSurfaceDisabled() : (checked || indeterminate) ? Primary() : OnSurfaceMedium();
    
    if (checked || indeterminate) {
        drawList->AddRectFilled(boxMin, boxMax, boxColor, 2.0f);
        
        if (indeterminate) {
            // Horizontal line for indeterminate
            drawList->AddLine(
                ImVec2(boxMin.x + 4, centerY),
                ImVec2(boxMax.x - 4, centerY),
                OnPrimary(), 2.0f
            );
        } else {
            // Checkmark
            ImVec2 checkStart(boxMin.x + 4, centerY);
            ImVec2 checkMid(boxMin.x + 7, centerY + 3);
            ImVec2 checkEnd(boxMin.x + 14, centerY - 4);
            drawList->AddLine(checkStart, checkMid, OnPrimary(), 2.0f);
            drawList->AddLine(checkMid, checkEnd, OnPrimary(), 2.0f);
        }
    } else {
        drawList->AddRect(boxMin, boxMax, boxColor, 2.0f, 0, 2.0f);
    }
    
    if (hovered && !disabled) {
        ImVec2 boxCenter((boxMin.x + boxMax.x) * 0.5f, centerY);
        drawList->AddCircleFilled(boxCenter, boxSize, schema::UI().resolveColor("var(--hover-overlay)", IM_COL32(255, 255, 255, 25)));
    }
    
    ImVec2 labelPos(pos.x + boxSize + spacing::dp(2), pos.y + (totalHeight - ImGui::GetFontSize()) * 0.5f);
    ImU32 labelColor = disabled ? OnSurfaceDisabled() : OnSurface();
    drawList->AddText(labelPos, labelColor, label);
    
    ImGui::PopID();
    
    return changed;
}

inline bool RadioButton(const char* label, bool active, bool disabled) {
    ImGuiWindow* window = ImGui::GetCurrentWindow();
    if (window->SkipItems)
        return false;
    
    ImGui::PushID(label);
    
    // Radio button dimensions (20dp outer, 10dp inner when selected)
    const float outerRadius = 10.0f;
    const float innerRadius = 5.0f;
    
    ImVec2 pos = window->DC.CursorPos;
    float labelWidth = ImGui::CalcTextSize(label).x;
    float totalWidth = outerRadius * 2 + spacing::dp(2) + labelWidth;
    float totalHeight = size::TouchTarget;
    
    ImRect bb(pos, ImVec2(pos.x + totalWidth, pos.y + totalHeight));
    
    ImGuiID id = window->GetID("##radio");
    ImGui::ItemSize(bb);
    if (!ImGui::ItemAdd(bb, id))
        return false;
    
    bool hovered, held;
    bool pressed = ImGui::ButtonBehavior(bb, id, &hovered, &held) && !disabled;
    
    ImDrawList* drawList = window->DrawList;
    float centerY = pos.y + totalHeight * 0.5f;
    ImVec2 center(pos.x + outerRadius, centerY);
    
    ImU32 ringColor = disabled ? OnSurfaceDisabled() : active ? Primary() : OnSurfaceMedium();
    
    // Outer ring
    drawList->AddCircle(center, outerRadius, ringColor, 0, 2.0f);
    
    // Inner dot when active
    if (active) {
        drawList->AddCircleFilled(center, innerRadius, ringColor);
    }
    
    // Hover ripple
    if (hovered && !disabled) {
        drawList->AddCircleFilled(center, outerRadius + 12.0f,
            active ? WithAlpha(Primary(), 25) : schema::UI().resolveColor("var(--hover-overlay)", IM_COL32(255, 255, 255, 25)));
    }
    
    // Label
    ImVec2 labelPos(pos.x + outerRadius * 2 + spacing::dp(2), pos.y + (totalHeight - ImGui::GetFontSize()) * 0.5f);
    ImU32 labelColor = disabled ? OnSurfaceDisabled() : OnSurface();
    drawList->AddText(labelPos, labelColor, label);
    
    ImGui::PopID();
    
    return pressed;
}

inline bool RadioButton(const char* label, int* selection, int value, bool disabled) {
    bool active = (*selection == value);
    if (RadioButton(label, active, disabled)) {
        *selection = value;
        return true;
    }
    return false;
}

} // namespace material
} // namespace ui
} // namespace dragonx
