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

#pragma once

#include <string>
#include <cstdio>
#include <cstring>
#include <cmath>
#include "../../app.h"
#include "../../util/i18n.h"
#include "../material/draw_helpers.h"
#include "../notifications.h"
#include "../theme.h"
#include "imgui.h"

namespace dragonx {
namespace ui {

/**
 * @brief Modal dialog for transferring funds between two addresses.
 *
 * Shown when a user drags one address row onto another in the address list.
 * Displays from/to addresses, balances, amount input, fee, and a preview of
 * the resulting balances after transfer.
 */
struct AddressTransferInfo {
    std::string fromAddr;
    std::string toAddr;
    double fromBalance = 0.0;
    double toBalance   = 0.0;
    bool fromIsZ = false;
    bool toIsZ   = false;
};

class AddressTransferDialog {
public:
    using TransferInfo = AddressTransferInfo;

    static void show(App* app, const TransferInfo& info) {
        s_open = true;
        s_app = app;
        s_info = info;
        s_sending = false;
        s_resultMsg.clear();
        s_success = false;

        // Default fee
        s_fee = 0.0001;

        // Pre-fill with the maximum sendable amount so the dialog is valid
        // immediately without requiring the user to press Max.
        snprintf(s_amount, sizeof(s_amount), "%.8f", maxSendableAmount(info.fromBalance, s_fee));
    }

    static void render() {
        if (!s_open || !s_app) return;

        using namespace material;

        OverlayDialogSpec ov;
        ov.title = TR("transfer_funds"); ov.p_open = &s_open;
        ov.style = OverlayStyle::BlurFloat;
        ov.cardWidth = 620.0f; ov.idSuffix = "addrtransfer";
        if (BeginOverlayDialog(ov)) {
            float dp = Layout::dpiScale();
            ImDrawList* dl = ImGui::GetWindowDrawList();

            // If we got a result, show it
            if (!s_resultMsg.empty()) {
                renderResult();
                EndOverlayDialog();
                return;
            }

            // Shielding / deshielding warning
            if (s_info.fromIsZ && !s_info.toIsZ) {
                DialogWarningHeader(TR("deshielding_warning"));
                ImGui::Spacing();
            } else if (!s_info.fromIsZ && s_info.toIsZ) {
                ImGui::PushStyleColor(ImGuiCol_Text, ImGui::ColorConvertU32ToFloat4(Success()));
                ImGui::TextWrapped("%s", TR("shielding_notice"));
                ImGui::PopStyleColor();
                ImGui::Spacing();
            }

            // From address
            Type().text(TypeStyle::Overline, TR("from"));
            renderAddressRow(s_info.fromAddr, s_info.fromBalance, s_info.fromIsZ, dp);
            ImGui::Spacing();

            // Arrow
            {
                float arrowCX = ImGui::GetContentRegionAvail().x * 0.5f;
                ImGui::SetCursorPosX(arrowCX - 8.0f * dp);
                ImFont* iconFont = Type().iconMed();
                float fsz = ScaledFontSize(iconFont);
                ImVec2 pos = ImGui::GetCursorScreenPos();
                dl->AddText(iconFont, fsz, pos, OnSurfaceMedium(), ICON_MD_ARROW_DOWNWARD);
                ImGui::Dummy(ImVec2(fsz, fsz));
            }
            ImGui::Spacing();

            // To address
            Type().text(TypeStyle::Overline, TR("to"));
            renderAddressRow(s_info.toAddr, s_info.toBalance, s_info.toIsZ, dp);
            ImGui::Spacing();
            ImGui::Spacing();

            // Amount input + Max button on same row without overflow
            Type().text(TypeStyle::Subtitle2, TR("amount"));
            {
                float spacing = ImGui::GetStyle().ItemSpacing.x;
                float maxBtnW = ImGui::CalcTextSize(TR("max")).x
                                + ImGui::GetStyle().FramePadding.x * 2.0f;
                ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x - maxBtnW - spacing);
            }
            ImGui::InputText("##TransferAmt", s_amount, sizeof(s_amount),
                ImGuiInputTextFlags_CharsDecimal);

            // Max button
            ImGui::SameLine();
            if (material::TactileSmallButton(TR("max"))) {
                snprintf(s_amount, sizeof(s_amount), "%.8f",
                    maxSendableAmount(s_info.fromBalance, s_fee));
            }
            ImGui::Spacing();

            // Fee display
            {
                char feeBuf[64];
                snprintf(feeBuf, sizeof(feeBuf), "%s: %.4f DRGX", TR("fee"), s_fee);
                Type().textColored(TypeStyle::Caption, OnSurfaceDisabled(), feeBuf);
            }
            ImGui::Spacing();

            // Preview after transfer
            double amount = atof(s_amount);
            double totalDeduct = amount + s_fee;
            double newFromBal = s_info.fromBalance - totalDeduct;
            double newToBal = s_info.toBalance + amount;
            bool amountValid = amount > 0 && totalDeduct <= s_info.fromBalance;

            ImGui::Separator();
            ImGui::Spacing();
            Type().text(TypeStyle::Subtitle2, TR("result_preview"));
            ImGui::Spacing();
            {
                char buf[128];
                snprintf(buf, sizeof(buf), TR("sender_balance"),
                    s_info.fromBalance, amountValid ? newFromBal : s_info.fromBalance);
                Type().textColored(TypeStyle::Caption,
                    (amountValid && newFromBal < 1e-9) ? Warning() : OnSurfaceMedium(), buf);
            }
            {
                char buf[128];
                snprintf(buf, sizeof(buf), TR("recipient_balance"),
                    s_info.toBalance, amountValid ? newToBal : s_info.toBalance);
                Type().textColored(TypeStyle::Caption, OnSurfaceMedium(), buf);
            }

            // Warnings
            if (!amountValid && amount > 0) {
                ImGui::Spacing();
                ImGui::PushStyleColor(ImGuiCol_Text, ImGui::ColorConvertU32ToFloat4(Error()));
                ImGui::TextWrapped("%s", TR("insufficient_funds"));
                ImGui::PopStyleColor();
            }
            if (amountValid && newFromBal < 1e-9) {
                ImGui::Spacing();
                // Full-balance send: same warning-icon treatment as the de-shielding header above,
                // so this stakes-bearing line reads as distinct from the neutral preview text.
                DialogWarningHeader(TR("sends_full_balance_warning"));
            }

            // Buttons
            const char* cancelLabel = TR("cancel");
            const char* confirmLabel = TR("confirm_transfer");
            const char* sendingLabel = TR("sending");
            ImFont* buttonFont = Type().button();
            float buttonFontSize = ScaledFontSize(buttonFont);
            float confirmMinW = 160.0f * dp;
            float buttonPadW = ImGui::GetStyle().FramePadding.x * 2.0f + 24.0f * dp;
            // Both footer buttons share one width (equal-width primary/Close pair), sized to fit the
            // widest label — the "Sending…" swap label included — so nothing clips.
            float confirmTextW = std::max(
                buttonFont->CalcTextSizeA(buttonFontSize, 1000.0f, 0.0f, confirmLabel).x,
                buttonFont->CalcTextSizeA(buttonFontSize, 1000.0f, 0.0f, sendingLabel).x);
            float btnW = std::max(confirmMinW, confirmTextW + buttonPadW);
            float footerH = ImGui::GetFrameHeight() + ImGui::GetStyle().ItemSpacing.y * 3.0f;  // footer divider removed
            ImGuiViewport* vp = ImGui::GetMainViewport();
            float cardBottomY = vp->Pos.y + vp->Size.y * 0.85f;
            float footerTopY = cardBottomY - 24.0f * dp - footerH;
            float currentY = ImGui::GetCursorScreenPos().y;
            if (currentY < footerTopY) {
                ImGui::Dummy(ImVec2(0, footerTopY - currentY));
            } else {
                ImGui::Spacing();
            }

            // Standardized primary + Close footer (centered, no divider). The primary is the
            // Confirm/"Sending…" action; the Close button dismisses the dialog.
            bool outConfirm = false;
            bool outClose = false;
            DialogActionFooter(s_sending ? sendingLabel : confirmLabel,
                               amountValid && !s_sending,
                               cancelLabel, outConfirm, outClose, btnW);

            if (outClose) {
                s_open = false;
            }
            if (outConfirm) {
                s_sending = true;
                s_app->sendTransaction(s_info.fromAddr, s_info.toAddr,
                    amount, s_fee, "",
                    [](bool ok, const std::string& result) {
                        s_sending = false;
                        s_success = ok;
                        s_resultMsg = result;
                        if (ok) {
                            Notifications::instance().success(TR("transfer_sent_desc"));
                        } else {
                            Notifications::instance().error(result.empty() ? TR("transfer_failed") : result);
                        }
                    });
                // Keep the dialog OPEN on submit: s_sending drives the button to a disabled "Sending…"
                // state, and when the async callback sets s_resultMsg the in-dialog result screen shows
                // (with its own Close button). Previously closing here made that result screen dead code.
            }

            EndOverlayDialog();
        }
    }

    static bool isOpen() { return s_open; }
    static void close() { s_open = false; }

private:
    static double maxSendableAmount(double balance, double fee) {
        double maxAmt = balance - fee;
        return maxAmt > 0.0 ? maxAmt : 0.0;
    }

    static void renderAddressRow(const std::string& addr, double balance, bool isZ, float dp) {
        using namespace material;
        ImDrawList* dl = ImGui::GetWindowDrawList();
        ImVec2 pos = ImGui::GetCursorScreenPos();
        float w = ImGui::GetContentRegionAvail().x;
        float h = 40.0f * dp;
        ImVec2 mn = pos, mx(pos.x + w, pos.y + h);

        GlassPanelSpec g;
        g.rounding = 8.0f * dp;
        g.fillAlpha = 18;
        DrawGlassPanel(dl, mn, mx, g);

        float pad = 12.0f * dp;
        // Type icon
        ImFont* iconFont = Type().iconSmall();
        const char* icon = isZ ? ICON_MD_SHIELD : ICON_MD_CIRCLE;
        ImU32 col = isZ ? Success() : Warning();
        float iconFsz = ScaledFontSize(iconFont);
        ImVec2 iSz = iconFont->CalcTextSizeA(iconFsz, 1000.0f, 0.0f, icon);
        dl->AddText(iconFont, iconFsz, ImVec2(mn.x + pad, mn.y + (h - iSz.y) * 0.5f), col, icon);

        // Address (truncated)
        // Balance (right-aligned) — computed first so we know how much space address gets
        char balBuf[32];
        snprintf(balBuf, sizeof(balBuf), "%.8f DRGX", balance);
        ImFont* body = Type().body2();
        float bodyFsz = ScaledFontSize(body);
        ImVec2 balSz = body->CalcTextSizeA(bodyFsz, 1000.0f, 0.0f, balBuf);
        float balX = mx.x - pad - balSz.x;
        dl->AddText(body, bodyFsz, ImVec2(balX, mn.y + (h - balSz.y) * 0.5f),
            balance > 0 ? OnSurface() : OnSurfaceDisabled(), balBuf);

        float textX = mn.x + pad + iSz.x + 8.0f * dp;
        ImFont* capFont = Type().caption();
        float capFsz = ScaledFontSize(capFont);
        // Clip address text so it never overlaps the balance
        float addrMaxW = balX - textX - 8.0f * dp;
        dl->PushClipRect(ImVec2(textX, mn.y), ImVec2(textX + addrMaxW, mn.y + h), true);
        dl->AddText(capFont, capFsz, ImVec2(textX, mn.y + (h * 0.5f - capFsz)), OnSurfaceMedium(), addr.c_str());
        dl->PopClipRect();

        ImGui::Dummy(ImVec2(w, h));
    }

    static void renderResult() {
        using namespace material;
        if (s_success) {
            ImGui::Spacing();
            Type().text(TypeStyle::H6, TR("transfer_sent"));
            ImGui::Spacing();
            Type().textColored(TypeStyle::Caption, OnSurfaceMedium(), TR("transfer_sent_desc"));
            ImGui::Spacing();
            {
                char buf[128];
                snprintf(buf, sizeof(buf), TR("shield_operation_id"),
                    s_resultMsg.size() > 40
                        ? (s_resultMsg.substr(0, 20) + "..." + s_resultMsg.substr(s_resultMsg.size() - 10)).c_str()
                        : s_resultMsg.c_str());
                Type().textColored(TypeStyle::Caption, OnSurfaceDisabled(), buf);
            }
        } else {
            ImGui::Spacing();
            Type().textColored(TypeStyle::H6, Error(), TR("transfer_failed"));
            ImGui::Spacing();
            ImGui::TextWrapped("%s", s_resultMsg.c_str());
        }

        ImGui::Spacing();
        ImGui::Spacing();
        const float dp = Layout::dpiScale();
        float btnW = 120.0f * dp;
        ImGui::SetCursorPosX((ImGui::GetContentRegionAvail().x - btnW) * 0.5f);
        if (TactileButton(TR("close"), ImVec2(btnW, 0))) {
            s_open = false;
        }
    }

    static inline bool s_open = false;
    static inline App* s_app = nullptr;
    static inline TransferInfo s_info;
    static inline char s_amount[64] = {};
    static inline double s_fee = 0.0001;
    static inline bool s_sending = false;
    static inline bool s_success = false;
    static inline std::string s_resultMsg;
};

} // namespace ui
} // namespace dragonx
