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

#pragma once

#include "colors.h"
#include "../effects/low_spec.h"
#include "imgui.h"
#include "imgui_internal.h"
#include <vector>
#include <cmath>

namespace dragonx {
namespace ui {
namespace material {

// ============================================================================
// Material Design Ripple Effect
// ============================================================================
// Based on https://m2.material.io/design/motion/customization.html
//
// Ripple effects provide visual feedback when users touch interactive elements.
// The ripple emanates from the touch point and expands outward.

/**
 * @brief Individual ripple instance
 */
struct Ripple {
    ImVec2 center;          // Ripple center point
    float startTime;        // When ripple started
    float maxRadius;        // Maximum expansion radius
    ImU32 color;            // Ripple color
    bool releasing;         // True when finger lifted
    float releaseTime;      // When release started
    
    Ripple(const ImVec2& center, float maxRadius, ImU32 color, float currentTime)
        : center(center)
        , startTime(currentTime)
        , maxRadius(maxRadius)
        , color(color)
        , releasing(false)
        , releaseTime(0)
    {}
};

/**
 * @brief Ripple effect manager
 * 
 * Manages ripple animations for interactive elements.
 */
class RippleManager {
public:
    static RippleManager& instance();
    
    /**
     * @brief Start a new ripple
     * 
     * @param id Widget ID
     * @param center Ripple center (touch point)
     * @param maxRadius Maximum ripple radius
     * @param color Ripple color (typically primary with low alpha)
     */
    void startRipple(ImGuiID id, const ImVec2& center, float maxRadius, ImU32 color);
    
    /**
     * @brief Release current ripple (finger lifted)
     */
    void releaseRipple(ImGuiID id);
    
    /**
     * @brief Draw ripple effect for a widget
     * 
     * @param drawList Draw list to use
     * @param id Widget ID
     * @param clipRect Clip rectangle for the ripple
     * @param cornerRadius Corner radius for clip shape
     */
    void drawRipple(ImDrawList* drawList, ImGuiID id, const ImRect& clipRect, 
                    float cornerRadius = 0);
    
    /**
     * @brief Update all ripples (call once per frame)
     */
    void update();
    
    /**
     * @brief Clear all ripples
     */
    void clear();
    
private:
    RippleManager() = default;
    
    struct RippleEntry {
        ImGuiID id;
        Ripple ripple;
    };
    
    std::vector<RippleEntry> m_ripples;
    
    static constexpr float kExpandDuration = 0.3f;    // 300ms to full size
    static constexpr float kFadeDuration = 0.2f;      // 200ms fade out
    static constexpr float kMaxOpacity = 0.12f;       // 12% max opacity
};

// ============================================================================
// Convenience Functions
// ============================================================================

/**
 * @brief Draw ripple effect for a button/interactive element
 * 
 * Call this after drawing the element background but before text/content.
 * 
 * @param drawList Draw list
 * @param rect Element bounds
 * @param id Element ID
 * @param cornerRadius Corner radius
 * @param hovered Is element hovered
 * @param held Is element being pressed
 * @param color Optional ripple color (default: white for dark theme)
 */
void DrawRippleEffect(ImDrawList* drawList, const ImRect& rect, ImGuiID id,
                      float cornerRadius = 0, bool hovered = false, bool held = false,
                      ImU32 color = IM_COL32(255, 255, 255, 255));

/**
 * @brief Update ripple system (call once per frame in main loop)
 */
void UpdateRipples();

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

inline RippleManager& RippleManager::instance() {
    static RippleManager s_instance;
    return s_instance;
}

inline void RippleManager::startRipple(ImGuiID id, const ImVec2& center, 
                                        float maxRadius, ImU32 color) {
    float currentTime = (float)ImGui::GetTime();
    
    // Check if ripple already exists for this ID
    for (auto& entry : m_ripples) {
        if (entry.id == id) {
            // Reset existing ripple
            entry.ripple = Ripple(center, maxRadius, color, currentTime);
            return;
        }
    }
    
    // Add new ripple
    m_ripples.push_back({id, Ripple(center, maxRadius, color, currentTime)});
}

inline void RippleManager::releaseRipple(ImGuiID id) {
    float currentTime = (float)ImGui::GetTime();
    
    for (auto& entry : m_ripples) {
        if (entry.id == id && !entry.ripple.releasing) {
            entry.ripple.releasing = true;
            entry.ripple.releaseTime = currentTime;
        }
    }
}

inline void RippleManager::drawRipple(ImDrawList* drawList, ImGuiID id, 
                                       const ImRect& clipRect, float cornerRadius) {
    float currentTime = (float)ImGui::GetTime();
    
    for (const auto& entry : m_ripples) {
        if (entry.id != id)
            continue;
        
        const Ripple& ripple = entry.ripple;
        
        // Calculate expansion progress
        float expandProgress = (currentTime - ripple.startTime) / kExpandDuration;
        expandProgress = ImClamp(expandProgress, 0.0f, 1.0f);
        
        // Deceleration easing for expansion
        expandProgress = 1.0f - (1.0f - expandProgress) * (1.0f - expandProgress);
        
        float currentRadius = ripple.maxRadius * expandProgress;
        
        // Calculate opacity
        float opacity = kMaxOpacity;
        
        if (ripple.releasing) {
            float fadeProgress = (currentTime - ripple.releaseTime) / kFadeDuration;
            fadeProgress = ImClamp(fadeProgress, 0.0f, 1.0f);
            opacity *= (1.0f - fadeProgress);
        }
        
        if (opacity <= 0.001f)
            continue;
        
        // Extract color components
        float r = ((ripple.color >> IM_COL32_R_SHIFT) & 0xFF) / 255.0f;
        float g = ((ripple.color >> IM_COL32_G_SHIFT) & 0xFF) / 255.0f;
        float b = ((ripple.color >> IM_COL32_B_SHIFT) & 0xFF) / 255.0f;
        ImU32 rippleColor = ImGui::ColorConvertFloat4ToU32(ImVec4(r, g, b, opacity));
        
        // Push clip rect for rounded corners
        if (cornerRadius > 0) {
            // For rounded rectangles, we approximate with the clip rect
            // A perfect solution would require custom clipping
            drawList->PushClipRect(clipRect.Min, clipRect.Max, true);
        }
        
        // Draw ripple circle (skip expanding animation in low-spec mode)
        if (!dragonx::ui::effects::isLowSpecMode())
            drawList->AddCircleFilled(ripple.center, currentRadius, rippleColor, 32);
        
        if (cornerRadius > 0) {
            drawList->PopClipRect();
        }
        
        break;  // Only one ripple per ID
    }
}

inline void RippleManager::update() {
    float currentTime = (float)ImGui::GetTime();
    
    // Remove completed ripples
    m_ripples.erase(
        std::remove_if(m_ripples.begin(), m_ripples.end(),
            [currentTime](const RippleEntry& entry) {
                if (!entry.ripple.releasing)
                    return false;
                float fadeProgress = (currentTime - entry.ripple.releaseTime) / kFadeDuration;
                return fadeProgress >= 1.0f;
            }
        ),
        m_ripples.end()
    );
}

inline void RippleManager::clear() {
    m_ripples.clear();
}

inline void DrawRippleEffect(ImDrawList* drawList, const ImRect& rect, ImGuiID id,
                             float cornerRadius, bool hovered, bool held, ImU32 color) {
    RippleManager& manager = RippleManager::instance();
    
    // Start ripple on press
    if (held && ImGui::IsMouseClicked(0)) {
        ImVec2 mousePos = ImGui::GetIO().MousePos;
        // Calculate max radius (distance from click to farthest corner)
        float dx1 = mousePos.x - rect.Min.x;
        float dy1 = mousePos.y - rect.Min.y;
        float dx2 = rect.Max.x - mousePos.x;
        float dy2 = rect.Max.y - mousePos.y;
        float maxDx = ImMax(dx1, dx2);
        float maxDy = ImMax(dy1, dy2);
        float maxRadius = std::sqrt(maxDx * maxDx + maxDy * maxDy) * 1.2f;
        
        manager.startRipple(id, mousePos, maxRadius, color);
    }
    
    // Release ripple when mouse released
    if (!held && !ImGui::IsMouseDown(0)) {
        manager.releaseRipple(id);
    }
    
    // Draw the ripple
    manager.drawRipple(drawList, id, rect, cornerRadius);
    
    // Also draw hover state overlay
    if (hovered && !held) {
        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;
        ImU32 hoverColor = ImGui::ColorConvertFloat4ToU32(ImVec4(r, g, b, 0.04f));  // 4% overlay
        drawList->AddRectFilled(rect.Min, rect.Max, hoverColor, cornerRadius);
    }
}

inline void UpdateRipples() {
    RippleManager::instance().update();
}

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