// 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 "imgui.h"
#include "imgui_internal.h"

namespace dragonx {
namespace ui {
namespace material {

// ============================================================================
// Material Design Text Field Component
// ============================================================================
// Based on https://m2.material.io/components/text-fields
//
// Two variants:
// - Filled: Background fill with bottom line indicator
// - Outlined: Border around entire field

enum class TextFieldStyle {
    Filled,    // Background fill
    Outlined   // Border only
};

/**
 * @brief Text field configuration
 */
struct TextFieldSpec {
    TextFieldStyle style = TextFieldStyle::Outlined;
    const char* label = nullptr;       // Floating label text
    const char* hint = nullptr;        // Placeholder when empty
    const char* helperText = nullptr;  // Helper text below field
    const char* errorText = nullptr;   // Error message (shows in error state)
    const char* prefix = nullptr;      // Prefix text (e.g., "$")
    const char* suffix = nullptr;      // Suffix text (e.g., "DRGX")
    bool password = false;             // Mask input
    bool readOnly = false;             // Read-only field
    bool multiline = false;            // Multi-line text area
    int multilineRows = 3;             // Number of rows for multiline
    float width = 0;                   // Width (0 = full available)
};

/**
 * @brief Render a Material Design text field
 * 
 * @param id Unique identifier
 * @param buf Text buffer
 * @param bufSize Buffer size
 * @param spec Field configuration
 * @return true if value changed
 */
bool TextField(const char* id, char* buf, size_t bufSize, const TextFieldSpec& spec = TextFieldSpec());

/**
 * @brief Render a simple text field with label
 */
inline bool TextField(const char* label, char* buf, size_t bufSize) {
    TextFieldSpec spec;
    spec.label = label;
    return TextField(label, buf, bufSize, spec);
}

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

inline bool TextField(const char* id, char* buf, size_t bufSize, const TextFieldSpec& spec) {
    ImGuiWindow* window = ImGui::GetCurrentWindow();
    if (window->SkipItems)
        return false;
    
    ImGui::PushID(id);
    
    bool hasError = (spec.errorText != nullptr);
    bool hasValue = (buf[0] != '\0');
    
    // Calculate dimensions
    float fieldWidth = spec.width > 0 ? spec.width : ImGui::GetContentRegionAvail().x;
    float fieldHeight = spec.multiline ? 
        (size::TextFieldHeight + (spec.multilineRows - 1) * Typography::instance().getFont(TypeStyle::Body1)->FontSize * 1.5f) :
        size::TextFieldHeight;
    
    ImVec2 pos = window->DC.CursorPos;
    ImRect bb(pos, ImVec2(pos.x + fieldWidth, pos.y + fieldHeight));
    
    // Interaction
    ImGuiID inputId = window->GetID("##input");
    bool focused = (ImGui::GetFocusID() == inputId);
    
    // Colors
    ImU32 bgColor, borderColor, labelColor;
    
    if (hasError) {
        borderColor = Error();
        labelColor = Error();
    } else if (focused) {
        borderColor = Primary();
        labelColor = Primary();
    } else {
        borderColor = OnSurfaceMedium();
        labelColor = OnSurfaceMedium();
    }
    
    if (spec.style == TextFieldStyle::Filled) {
        bgColor = GetElevatedSurface(GetCurrentColorTheme(), 1);
    } else {
        bgColor = 0;  // Transparent for outlined
    }
    
    // Draw background/border
    ImDrawList* drawList = window->DrawList;
    
    if (spec.style == TextFieldStyle::Filled) {
        // Filled style: background with bottom line
        drawList->AddRectFilled(bb.Min, bb.Max, bgColor, 
                                size::TextFieldCornerRadius, ImDrawFlags_RoundCornersTop);
        
        // Bottom indicator line
        float lineThickness = focused ? 2.0f : 1.0f;
        drawList->AddLine(
            ImVec2(bb.Min.x, bb.Max.y - lineThickness),
            ImVec2(bb.Max.x, bb.Max.y - lineThickness),
            borderColor, lineThickness
        );
    } else {
        // Outlined style: border around entire field
        float lineThickness = focused ? 2.0f : 1.0f;
        drawList->AddRect(bb.Min, bb.Max, borderColor, 
                         size::TextFieldCornerRadius, 0, lineThickness);
    }
    
    // Label (floating or inline)
    bool labelFloating = focused || hasValue;
    if (spec.label) {
        ImVec2 labelPos;
        TypeStyle labelStyle;
        
        if (labelFloating) {
            // Floating label (smaller, at top)
            labelPos.x = bb.Min.x + size::TextFieldPadding;
            labelPos.y = bb.Min.y + 4.0f;
            labelStyle = TypeStyle::Caption;
        } else {
            // Inline label (body size, centered)
            labelPos.x = bb.Min.x + size::TextFieldPadding;
            labelPos.y = bb.Min.y + (fieldHeight - Typography::instance().getFont(TypeStyle::Body1)->FontSize) * 0.5f;
            labelStyle = TypeStyle::Body1;
        }
        
        // For outlined style, need to clear background behind floating label
        if (spec.style == TextFieldStyle::Outlined && labelFloating) {
            ImVec2 labelSize = ImGui::CalcTextSize(spec.label);
            ImVec2 clearMin(labelPos.x - 4.0f, bb.Min.y - 1.0f);
            ImVec2 clearMax(labelPos.x + labelSize.x + 4.0f, bb.Min.y + Typography::instance().getFont(TypeStyle::Caption)->FontSize);
            drawList->AddRectFilled(clearMin, clearMax, Background());
        }
        
        Typography::instance().pushFont(labelStyle);
        drawList->AddText(labelPos, labelColor, spec.label);
        Typography::instance().popFont();
    }
    
    // Input field
    float inputY = spec.label && labelFloating ? bb.Min.y + 20.0f : bb.Min.y + 12.0f;
    float inputHeight = bb.Max.y - inputY - 8.0f;
    
    ImGui::SetCursorScreenPos(ImVec2(bb.Min.x + size::TextFieldPadding, inputY));
    ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
    ImGui::PushStyleColor(ImGuiCol_FrameBg, IM_COL32(0, 0, 0, 0));
    ImGui::PushStyleColor(ImGuiCol_Text, ImGui::ColorConvertU32ToFloat4(OnSurface()));
    
    ImGuiInputTextFlags flags = 0;
    if (spec.password) flags |= ImGuiInputTextFlags_Password;
    if (spec.readOnly) flags |= ImGuiInputTextFlags_ReadOnly;
    
    float inputWidth = fieldWidth - size::TextFieldPadding * 2;
    if (spec.prefix) {
        ImGui::TextUnformatted(spec.prefix);
        ImGui::SameLine();
        inputWidth -= ImGui::CalcTextSize(spec.prefix).x + 4.0f;
    }
    
    ImGui::PushItemWidth(inputWidth);
    bool changed;
    if (spec.multiline) {
        changed = ImGui::InputTextMultiline("##input", buf, bufSize, 
            ImVec2(inputWidth, inputHeight), flags);
    } else {
        changed = ImGui::InputText("##input", buf, bufSize, flags);
    }
    ImGui::PopItemWidth();
    
    if (spec.suffix) {
        ImGui::SameLine();
        ImGui::TextColored(ImGui::ColorConvertU32ToFloat4(OnSurfaceMedium()), "%s", spec.suffix);
    }
    
    ImGui::PopStyleColor(2);
    ImGui::PopStyleVar();
    
    // Helper/Error text below field
    ImGui::SetCursorScreenPos(ImVec2(bb.Min.x, bb.Max.y + 4.0f));
    if (spec.errorText) {
        Typography::instance().textColored(TypeStyle::Caption, Error(), spec.errorText);
        ImGui::SetCursorScreenPos(ImVec2(bb.Min.x, bb.Max.y + 4.0f + Typography::instance().getFont(TypeStyle::Caption)->FontSize + 4.0f));
    } else if (spec.helperText) {
        Typography::instance().textColored(TypeStyle::Caption, OnSurfaceMedium(), spec.helperText);
        ImGui::SetCursorScreenPos(ImVec2(bb.Min.x, bb.Max.y + 4.0f + Typography::instance().getFont(TypeStyle::Caption)->FontSize + 4.0f));
    }
    
    // Advance cursor
    ImGui::SetCursorScreenPos(ImVec2(pos.x, bb.Max.y + (spec.errorText || spec.helperText ? 24.0f : 8.0f)));
    
    ImGui::PopID();
    
    return changed;
}

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