// 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 Slider Component
// ============================================================================
// Based on https://m2.material.io/components/sliders
//
// Sliders allow users to make selections from a range of values.

/**
 * @brief Continuous slider
 * 
 * @param label Label for the slider (hidden, used for ID)
 * @param value Pointer to current value
 * @param minValue Minimum value
 * @param maxValue Maximum value
 * @param format Printf format for value display (nullptr = no display)
 * @param width Slider width (0 = full available)
 * @return true if value changed
 */
bool Slider(const char* label, float* value, float minValue, float maxValue,
            const char* format = nullptr, float width = 0);

/**
 * @brief Integer slider
 */
bool SliderInt(const char* label, int* value, int minValue, int maxValue,
               const char* format = nullptr, float width = 0);

/**
 * @brief Discrete slider with steps
 * 
 * @param label Label for the slider
 * @param value Pointer to current value
 * @param minValue Minimum value
 * @param maxValue Maximum value
 * @param step Step size
 * @param showTicks Show tick marks
 * @return true if value changed
 */
bool SliderDiscrete(const char* label, float* value, float minValue, float maxValue,
                    float step, bool showTicks = true, float width = 0);

/**
 * @brief Range slider (two thumbs)
 * 
 * @param label Label for the slider
 * @param minVal Pointer to range minimum
 * @param maxVal Pointer to range maximum
 * @param rangeMin Allowed minimum
 * @param rangeMax Allowed maximum
 * @return true if either value changed
 */
bool SliderRange(const char* label, float* minVal, float* maxVal,
                 float rangeMin, float rangeMax, float width = 0);

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

inline bool Slider(const char* label, float* value, float minValue, float maxValue,
                   const char* format, float width) {
    ImGuiWindow* window = ImGui::GetCurrentWindow();
    if (window->SkipItems)
        return false;
    
    ImGui::PushID(label);
    
    // Slider dimensions
    const float trackHeight = 4.0f;
    const float thumbRadius = 10.0f;  // 20dp diameter
    float sliderWidth = width > 0 ? width : ImGui::GetContentRegionAvail().x;
    float totalHeight = size::TouchTarget;  // 48dp touch target
    
    ImVec2 pos = window->DC.CursorPos;
    ImRect bb(pos, ImVec2(pos.x + sliderWidth, pos.y + totalHeight));
    
    // Item interaction
    ImGuiID id = window->GetID("##slider");
    ImGui::ItemSize(bb);
    if (!ImGui::ItemAdd(bb, id))
        return false;
    
    bool hovered, held;
    bool pressed = ImGui::ButtonBehavior(bb, id, &hovered, &held);
    
    // Calculate thumb position
    float trackLeft = pos.x + thumbRadius;
    float trackRight = pos.x + sliderWidth - thumbRadius;
    float trackWidth = trackRight - trackLeft;
    float centerY = pos.y + totalHeight * 0.5f;
    
    float fraction = (*value - minValue) / (maxValue - minValue);
    fraction = ImClamp(fraction, 0.0f, 1.0f);
    float thumbX = trackLeft + trackWidth * fraction;
    
    // Handle dragging
    bool changed = false;
    if (held) {
        float mouseX = ImGui::GetIO().MousePos.x;
        float newFraction = (mouseX - trackLeft) / trackWidth;
        newFraction = ImClamp(newFraction, 0.0f, 1.0f);
        float newValue = minValue + newFraction * (maxValue - minValue);
        
        if (newValue != *value) {
            *value = newValue;
            changed = true;
        }
        thumbX = trackLeft + trackWidth * newFraction;
    }
    
    // Draw
    ImDrawList* drawList = window->DrawList;
    
    // Track (inactive part)
    ImU32 trackInactiveColor = WithAlpha(Primary(), 64);  // Primary at 25%
    drawList->AddRectFilled(
        ImVec2(trackLeft, centerY - trackHeight * 0.5f),
        ImVec2(trackRight, centerY + trackHeight * 0.5f),
        trackInactiveColor, trackHeight * 0.5f
    );
    
    // Track (active part)
    drawList->AddRectFilled(
        ImVec2(trackLeft, centerY - trackHeight * 0.5f),
        ImVec2(thumbX, centerY + trackHeight * 0.5f),
        Primary(), trackHeight * 0.5f
    );
    
    // Thumb shadow
    drawList->AddCircleFilled(ImVec2(thumbX + 1, centerY + 2), thumbRadius, schema::UI().resolveColor("var(--control-shadow)", IM_COL32(0, 0, 0, 60)));
    
    // Thumb
    drawList->AddCircleFilled(ImVec2(thumbX, centerY), thumbRadius, Primary());
    
    // Hover/pressed ripple
    if (hovered || held) {
        ImU32 rippleColor = WithAlpha(Primary(), held ? 51 : 25);
        drawList->AddCircleFilled(ImVec2(thumbX, centerY), thumbRadius + 12.0f, rippleColor);
    }
    
    // Value label (when held)
    if (held && format) {
        char valueText[64];
        snprintf(valueText, sizeof(valueText), format, *value);
        
        ImVec2 textSize = ImGui::CalcTextSize(valueText);
        float labelY = centerY - thumbRadius - 32.0f;
        float labelX = thumbX - textSize.x * 0.5f;
        
        // Label background (rounded rectangle)
        float labelPadX = 8.0f;
        float labelPadY = 4.0f;
        ImVec2 labelMin(labelX - labelPadX, labelY - labelPadY);
        ImVec2 labelMax(labelX + textSize.x + labelPadX, labelY + textSize.y + labelPadY);
        
        drawList->AddRectFilled(labelMin, labelMax, Primary(), 4.0f);
        drawList->AddText(ImVec2(labelX, labelY), OnPrimary(), valueText);
    }
    
    ImGui::PopID();
    
    return changed;
}

inline bool SliderInt(const char* label, int* value, int minValue, int maxValue,
                      const char* format, float width) {
    float floatVal = (float)*value;
    bool changed = Slider(label, &floatVal, (float)minValue, (float)maxValue, format, width);
    if (changed) {
        *value = (int)roundf(floatVal);
    }
    return changed;
}

inline bool SliderDiscrete(const char* label, float* value, float minValue, float maxValue,
                           float step, bool showTicks, float width) {
    ImGuiWindow* window = ImGui::GetCurrentWindow();
    if (window->SkipItems)
        return false;
    
    ImGui::PushID(label);
    
    const float trackHeight = 4.0f;
    const float thumbRadius = 10.0f;
    const float tickRadius = 2.0f;
    float sliderWidth = width > 0 ? width : ImGui::GetContentRegionAvail().x;
    float totalHeight = size::TouchTarget;
    
    ImVec2 pos = window->DC.CursorPos;
    ImRect bb(pos, ImVec2(pos.x + sliderWidth, pos.y + totalHeight));
    
    ImGuiID id = window->GetID("##slider");
    ImGui::ItemSize(bb);
    if (!ImGui::ItemAdd(bb, id))
        return false;
    
    bool hovered, held;
    ImGui::ButtonBehavior(bb, id, &hovered, &held);
    
    float trackLeft = pos.x + thumbRadius;
    float trackRight = pos.x + sliderWidth - thumbRadius;
    float trackWidth = trackRight - trackLeft;
    float centerY = pos.y + totalHeight * 0.5f;
    
    // Snap to step
    float snappedValue = roundf((*value - minValue) / step) * step + minValue;
    snappedValue = ImClamp(snappedValue, minValue, maxValue);
    
    float fraction = (snappedValue - minValue) / (maxValue - minValue);
    float thumbX = trackLeft + trackWidth * fraction;
    
    bool changed = false;
    if (held) {
        float mouseX = ImGui::GetIO().MousePos.x;
        float newFraction = (mouseX - trackLeft) / trackWidth;
        newFraction = ImClamp(newFraction, 0.0f, 1.0f);
        float rawValue = minValue + newFraction * (maxValue - minValue);
        float newValue = roundf((rawValue - minValue) / step) * step + minValue;
        newValue = ImClamp(newValue, minValue, maxValue);
        
        if (newValue != *value) {
            *value = newValue;
            changed = true;
        }
        fraction = (newValue - minValue) / (maxValue - minValue);
        thumbX = trackLeft + trackWidth * fraction;
    }
    
    ImDrawList* drawList = window->DrawList;
    
    // Track
    drawList->AddRectFilled(
        ImVec2(trackLeft, centerY - trackHeight * 0.5f),
        ImVec2(trackRight, centerY + trackHeight * 0.5f),
        WithAlpha(Primary(), 64), trackHeight * 0.5f
    );
    
    drawList->AddRectFilled(
        ImVec2(trackLeft, centerY - trackHeight * 0.5f),
        ImVec2(thumbX, centerY + trackHeight * 0.5f),
        Primary(), trackHeight * 0.5f
    );
    
    // Tick marks
    if (showTicks) {
        int numSteps = (int)((maxValue - minValue) / step);
        for (int i = 0; i <= numSteps; i++) {
            float tickFraction = (float)i / numSteps;
            float tickX = trackLeft + trackWidth * tickFraction;
            
            ImU32 tickColor = (tickX <= thumbX) ? OnPrimary() : WithAlpha(Primary(), 128);
            drawList->AddCircleFilled(ImVec2(tickX, centerY), tickRadius, tickColor);
        }
    }
    
    // Thumb
    drawList->AddCircleFilled(ImVec2(thumbX + 1, centerY + 2), thumbRadius, schema::UI().resolveColor("var(--control-shadow)", IM_COL32(0, 0, 0, 60)));
    drawList->AddCircleFilled(ImVec2(thumbX, centerY), thumbRadius, Primary());
    
    if (hovered || held) {
        ImU32 rippleColor = WithAlpha(Primary(), held ? 51 : 25);
        drawList->AddCircleFilled(ImVec2(thumbX, centerY), thumbRadius + 12.0f, rippleColor);
    }
    
    ImGui::PopID();
    
    return changed;
}

inline bool SliderRange(const char* label, float* minVal, float* maxVal,
                        float rangeMin, float rangeMax, float width) {
    ImGuiWindow* window = ImGui::GetCurrentWindow();
    if (window->SkipItems)
        return false;
    
    ImGui::PushID(label);
    
    const float trackHeight = 4.0f;
    const float thumbRadius = 10.0f;
    float sliderWidth = width > 0 ? width : ImGui::GetContentRegionAvail().x;
    float totalHeight = size::TouchTarget;
    
    ImVec2 pos = window->DC.CursorPos;
    ImRect bb(pos, ImVec2(pos.x + sliderWidth, pos.y + totalHeight));
    
    ImGuiID id = window->GetID("##slider");
    ImGui::ItemSize(bb);
    if (!ImGui::ItemAdd(bb, id))
        return false;
    
    float trackLeft = pos.x + thumbRadius;
    float trackRight = pos.x + sliderWidth - thumbRadius;
    float trackWidth = trackRight - trackLeft;
    float centerY = pos.y + totalHeight * 0.5f;
    
    float minFraction = (*minVal - rangeMin) / (rangeMax - rangeMin);
    float maxFraction = (*maxVal - rangeMin) / (rangeMax - rangeMin);
    float minThumbX = trackLeft + trackWidth * minFraction;
    float maxThumbX = trackLeft + trackWidth * maxFraction;
    
    // Hit test both thumbs
    ImVec2 mousePos = ImGui::GetIO().MousePos;
    float distToMin = fabsf(mousePos.x - minThumbX);
    float distToMax = fabsf(mousePos.x - maxThumbX);
    bool nearMin = distToMin < distToMax;
    
    ImGuiID minId = window->GetID("##min");
    ImGuiID maxId = window->GetID("##max");
    
    bool minHovered, minHeld;
    bool maxHovered, maxHeld;
    ImRect minHitBox(ImVec2(minThumbX - thumbRadius - 8, centerY - thumbRadius - 8),
                     ImVec2(minThumbX + thumbRadius + 8, centerY + thumbRadius + 8));
    ImRect maxHitBox(ImVec2(maxThumbX - thumbRadius - 8, centerY - thumbRadius - 8),
                     ImVec2(maxThumbX + thumbRadius + 8, centerY + thumbRadius + 8));
    
    ImGui::ButtonBehavior(nearMin ? minHitBox : maxHitBox, nearMin ? minId : maxId,
                          nearMin ? &minHovered : &maxHovered, 
                          nearMin ? &minHeld : &maxHeld);
    
    bool changed = false;
    
    if (minHeld) {
        float newFraction = (mousePos.x - trackLeft) / trackWidth;
        newFraction = ImClamp(newFraction, 0.0f, maxFraction - 0.01f);
        float newValue = rangeMin + newFraction * (rangeMax - rangeMin);
        if (newValue != *minVal) {
            *minVal = newValue;
            changed = true;
        }
        minThumbX = trackLeft + trackWidth * newFraction;
    }
    
    if (maxHeld) {
        float newFraction = (mousePos.x - trackLeft) / trackWidth;
        newFraction = ImClamp(newFraction, minFraction + 0.01f, 1.0f);
        float newValue = rangeMin + newFraction * (rangeMax - rangeMin);
        if (newValue != *maxVal) {
            *maxVal = newValue;
            changed = true;
        }
        maxThumbX = trackLeft + trackWidth * newFraction;
    }
    
    ImDrawList* drawList = window->DrawList;
    
    // Inactive track
    drawList->AddRectFilled(
        ImVec2(trackLeft, centerY - trackHeight * 0.5f),
        ImVec2(trackRight, centerY + trackHeight * 0.5f),
        WithAlpha(Primary(), 64), trackHeight * 0.5f
    );
    
    // Active track (between thumbs)
    drawList->AddRectFilled(
        ImVec2(minThumbX, centerY - trackHeight * 0.5f),
        ImVec2(maxThumbX, centerY + trackHeight * 0.5f),
        Primary(), trackHeight * 0.5f
    );
    
    // Min thumb
    drawList->AddCircleFilled(ImVec2(minThumbX + 1, centerY + 2), thumbRadius, schema::UI().resolveColor("var(--control-shadow)", IM_COL32(0, 0, 0, 60)));
    drawList->AddCircleFilled(ImVec2(minThumbX, centerY), thumbRadius, Primary());
    
    if (minHovered || minHeld) {
        ImU32 rippleColor = WithAlpha(Primary(), minHeld ? 51 : 25);
        drawList->AddCircleFilled(ImVec2(minThumbX, centerY), thumbRadius + 12.0f, rippleColor);
    }
    
    // Max thumb
    drawList->AddCircleFilled(ImVec2(maxThumbX + 1, centerY + 2), thumbRadius, schema::UI().resolveColor("var(--control-shadow)", IM_COL32(0, 0, 0, 60)));
    drawList->AddCircleFilled(ImVec2(maxThumbX, centerY), thumbRadius, Primary());
    
    if (maxHovered || maxHeld) {
        ImU32 rippleColor = WithAlpha(Primary(), maxHeld ? 51 : 25);
        drawList->AddCircleFilled(ImVec2(maxThumbX, centerY), thumbRadius + 12.0f, rippleColor);
    }
    
    ImGui::PopID();
    
    return changed;
}

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