// DragonX Wallet - ImGui Edition
// Copyright 2024-2026 The Hush Developers
// Released under the GPLv3
//
// Shared "click-to-copy field" widgets used by the key-export and QR-popup dialogs, so an address
// renders identically in both. A field is a bordered box of wrapping text whose whole area copies
// to the clipboard on click; long secrets/addresses are grouped into space-separated blocks.

#pragma once

#include <string>
#include <cstring>

#include "imgui.h"
#include "../material/colors.h"
#include "../material/tooltip_style.h"
#include "../../util/i18n.h"

namespace dragonx {
namespace ui {
namespace widgets {

// Draw `text` wrapped within wrapW with every visual line horizontally centered (returns the height
// used). ImGui has no center+wrap, so we walk the wrap points the way it would.
inline float DrawCenteredWrapped(ImDrawList* dl, ImFont* font, float fs, ImVec2 origin,
                                 float wrapW, ImU32 col, const char* text)
{
    const float scale = fs / font->LegacySize;
    const float lineH = ImGui::GetTextLineHeight();
    const char* s = text;
    const char* e = text + std::strlen(text);
    float y = origin.y;
    while (s < e) {
        const char* wrap = font->CalcWordWrapPositionA(scale, s, e, wrapW);
        if (wrap <= s) wrap = s + 1;
        const ImVec2 lw = font->CalcTextSizeA(fs, 1.0e30f, 0.0f, s, wrap);
        float lx = origin.x + (wrapW - lw.x) * 0.5f;
        if (lx < origin.x) lx = origin.x;
        dl->AddText(font, fs, ImVec2(lx, y), col, s, wrap);
        y += lineH;
        s = wrap;
        while (s < e && (*s == ' ' || *s == '\n')) s++;  // ImGui consumes the break char
    }
    return y - origin.y;
}

// Group a long string into space-separated blocks so it reads in scannable chunks and wraps on
// block boundaries. Callers copy the ORIGINAL (un-grouped) string.
inline std::string ChunkString(const std::string& s, size_t group)
{
    if (group == 0 || s.size() <= group) return s;
    std::string out;
    out.reserve(s.size() + s.size() / group + 1);
    for (size_t i = 0; i < s.size(); ++i) {
        if (i && (i % group) == 0) out.push_back(' ');
        out.push_back(s[i]);
    }
    return out;
}

// A wrapping, click-to-copy "field": draws `display` in a bordered box (the whole box is the copy
// affordance) and returns true when clicked. `center` centers each wrapped line. The caller is
// responsible for the actual clipboard write (so secrets can use an auto-clearing clipboard).
inline bool CopyField(const char* id, const std::string& display, float width, float minH, bool center)
{
    namespace m = material;
    ImDrawList* dl = ImGui::GetWindowDrawList();
    ImGuiStyle& st = ImGui::GetStyle();
    ImFont* font = ImGui::GetFont();
    const float fs = ImGui::GetFontSize();
    const float padX = st.FramePadding.x + 4.0f;
    const float padY = st.FramePadding.y + 4.0f;
    const float wrapW = (width - padX * 2.0f) > 1.0f ? (width - padX * 2.0f) : 1.0f;
    const ImVec2 ts = ImGui::CalcTextSize(display.c_str(), nullptr, false, wrapW);
    float h = ts.y + padY * 2.0f;
    if (h < minH) h = minH;
    const ImVec2 p0 = ImGui::GetCursorScreenPos();
    const ImVec2 p1 = ImVec2(p0.x + width, p0.y + h);
    ImGui::InvisibleButton(id, ImVec2(width, h));
    const bool hovered = ImGui::IsItemHovered();
    const bool clicked = ImGui::IsItemClicked();
    dl->AddRectFilled(p0, p1, m::WithAlpha(m::OnSurface(), hovered ? 18 : 8), 6.0f);
    dl->AddRect(p0, p1, m::WithAlpha(m::OnSurface(), hovered ? 70 : 30), 6.0f, 0, 1.0f);
    const float textY = p0.y + (h - ts.y) * 0.5f;  // vertical center
    if (center)
        DrawCenteredWrapped(dl, font, fs, ImVec2(p0.x + padX, textY), wrapW, m::OnSurface(), display.c_str());
    else
        dl->AddText(font, fs, ImVec2(p0.x + padX, textY), m::OnSurface(), display.c_str(), nullptr, wrapW);
    if (hovered) {
        ImGui::SetMouseCursor(ImGuiMouseCursor_Hand);
        material::Tooltip("%s", TR("copy"));
    }
    return clicked;
}

// An address field: chunked by 4 for readability, width clamped to its text, box centered in the
// available region. Copies the raw address to the clipboard on click; returns true when clicked.
inline bool AddressCopyField(const char* id, const std::string& address)
{
    const std::string at = ChunkString(address, 4);
    const float avail = ImGui::GetContentRegionAvail().x;
    const float padX = ImGui::GetStyle().FramePadding.x + 4.0f;
    float boxW = ImGui::CalcTextSize(at.c_str()).x + padX * 2.0f + 2.0f;  // clamp to text width
    if (boxW > avail) boxW = avail;
    ImGui::SetCursorPosX(ImGui::GetCursorPosX() + (avail > boxW ? (avail - boxW) * 0.5f : 0.0f));
    const bool clicked = CopyField(id, at, boxW, 0.0f, /*center=*/true);
    if (clicked) ImGui::SetClipboardText(address.c_str());
    return clicked;
}

} // namespace widgets
} // namespace ui
} // namespace dragonx
