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

#include "mining_mode_toggle.h"
#include "mining_tab_helpers.h"
#include "mining_tab.h"   // CancelMiningBenchmark (L-11)
#include "mining_pool_panel.h"

#include "../../app.h"
#include "../../config/version.h"
#include "../../config/settings.h"
#include "../../util/i18n.h"
#include "../../util/pool_registry.h"
#include "../../util/platform.h"
#include "../schema/ui_schema.h"
#include "../material/type.h"
#include "../material/draw_helpers.h"
#include "../material/colors.h"
#include "../../util/address_validation.h"   // isValidRecipientAddress — payout validation (M-01)
#include "../layout.h"
#include "../notifications.h"
#include "../../embedded/IconsMaterialDesign.h"
#include "imgui.h"
#include "imgui_internal.h"

#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <string>
#include <vector>

namespace dragonx {
namespace ui {

using namespace material;

void RenderMiningModeToggle(App* app, const WalletState& state, const MiningInfo& mining,
                            ImDrawList* dl, ImFont* capFont, ImFont* ovFont,
                            float dp, float hs, float gap, float availWidth,
                            bool& s_pool_mode, char (&s_pool_url)[256], char (&s_pool_worker)[256],
                            bool& s_pool_settings_dirty)
{
        // Arm/confirm for the destructive X (delete) on saved pools & workers: a first click on a
        // row's X arms it (the X turns red + relabels via the trash glyph) and a second click within
        // a short window actually removes it; moving to another row or letting the window lapse disarms.
        // Same idiom as contacts_tab.cpp's s_confirm_delete_idx, keyed by row index within each list.
        static int    s_armed_pool_idx   = -1;   // armed saved-pool row (-1 = none)
        static int    s_armed_worker_idx = -1;   // armed saved-worker row (-1 = none)
        static double s_armed_pool_time   = 0.0;
        static double s_armed_worker_time = 0.0;
        const double  kArmWindowSecs = 3.0;      // second click must land within this window
        const double  nowTime = ImGui::GetTime();
        // Lapse the arm if the confirm window elapsed.
        if (s_armed_pool_idx   >= 0 && nowTime - s_armed_pool_time   > kArmWindowSecs) s_armed_pool_idx   = -1;
        if (s_armed_worker_idx >= 0 && nowTime - s_armed_worker_time > kArmWindowSecs) s_armed_worker_idx = -1;

        const bool soloMiningAvailable = app->supportsSoloMining();
        float toggleW  = schema::UI().drawElement("tabs.mining", "mode-toggle-width").size * hs;
        float toggleH  = schema::UI().drawElement("tabs.mining", "mode-toggle-height").size * hs;
        float toggleRnd = schema::UI().drawElement("tabs.mining", "mode-toggle-rounding").size * hs;
        float totalW   = soloMiningAvailable ? (toggleW * 2) : toggleW;

        ImVec2 tMin = ImGui::GetCursorScreenPos();
        ImVec2 tMax(tMin.x + totalW, tMin.y + toggleH);

        // Glass background for the segmented control
        dl->AddRectFilled(tMin, tMax, WithAlpha(OnSurface(), 15), toggleRnd);
        dl->AddRect(tMin, tMax, WithAlpha(OnSurface(), 40), toggleRnd);

        ImVec2 soloMin = tMin;
        ImVec2 soloMax(tMin.x + toggleW, tMax.y);
        bool soloHov = material::IsRectHovered(soloMin, soloMax);
        if (soloMiningAvailable) {
            // SOLO button (left half)
            if (!s_pool_mode) {
                dl->AddRectFilled(soloMin, soloMax, WithAlpha(Primary(), 180), toggleRnd);
            } else if (soloHov) {
                dl->AddRectFilled(soloMin, soloMax, WithAlpha(OnSurface(), 20), toggleRnd);
            }
            const char* label = TR("mining_solo");
            ImVec2 sz = ovFont->CalcTextSizeA(ovFont->LegacySize, FLT_MAX, 0, label);
            float lx = soloMin.x + (toggleW - sz.x) * 0.5f;
            float ly = soloMin.y + (toggleH - sz.y) * 0.5f;
            ImU32 col = !s_pool_mode ? IM_COL32(255, 255, 255, 230) : OnSurfaceMedium();
            dl->AddText(ovFont, ovFont->LegacySize, ImVec2(lx, ly), col, label);
        }

        // POOL button (right half) — disabled when solo mining is active
        bool soloMiningActive = mining.generate;
        ImVec2 poolMin(tMin.x + (soloMiningAvailable ? toggleW : 0.0f), tMin.y);
        ImVec2 poolMax = tMax;
        bool poolHov = material::IsRectHovered(poolMin, poolMax);
        if (s_pool_mode) {
            dl->AddRectFilled(poolMin, poolMax, WithAlpha(Primary(), 180), toggleRnd);
        } else if (soloMiningActive) {
            // Dimmed — solo mining blocks pool mode
        } else if (poolHov) {
            dl->AddRectFilled(poolMin, poolMax, WithAlpha(OnSurface(), 20), toggleRnd);
        }
        {
            const char* label = TR("mining_pool");
            ImVec2 sz = ovFont->CalcTextSizeA(ovFont->LegacySize, FLT_MAX, 0, label);
            float lx = poolMin.x + (toggleW - sz.x) * 0.5f;
            float ly = poolMin.y + (toggleH - sz.y) * 0.5f;
            ImU32 col = s_pool_mode ? IM_COL32(255, 255, 255, 230)
                      : (soloMiningActive ? OnSurfaceDisabled() : OnSurfaceMedium());
            dl->AddText(ovFont, ovFont->LegacySize, ImVec2(lx, ly), col, label);
        }

        // Invisible buttons for click targets
        if (soloMiningAvailable) {
            ImGui::SetCursorScreenPos(soloMin);
            ImGui::InvisibleButton("##SoloMode", ImVec2(toggleW, toggleH));
            if (ImGui::IsItemClicked() && s_pool_mode) {
                s_pool_mode = false;
                app->settings()->setPoolMode(false);
                app->settings()->save();
                CancelMiningBenchmark(app);   // don't leave a pool benchmark running after switching to solo (L-11)
                app->stopPoolMining();
            }
            if (soloHov) ImGui::SetMouseCursor(ImGuiMouseCursor_Hand);
        }

        ImGui::SetCursorScreenPos(poolMin);
        ImGui::InvisibleButton("##PoolMode", ImVec2(toggleW, toggleH));
        if (soloMiningAvailable && ImGui::IsItemClicked() && !s_pool_mode && !soloMiningActive) {
            s_pool_mode = true;
            app->settings()->setPoolMode(true);
            app->settings()->save();
            // Note: soloMiningActive is already false (checked above),
            // so no need to call stopMining() — it would just set the
            // toggle-in-progress flag and make the button show "STARTING".
        }
        if (soloMiningAvailable && poolHov && !soloMiningActive) ImGui::SetMouseCursor(ImGuiMouseCursor_Hand);
        if (poolHov && soloMiningActive && !s_pool_mode) {
            material::Tooltip("%s", TR("mining_stop_solo_for_pool"));
        }

        ImGui::SetCursorScreenPos(ImVec2(tMin.x, tMax.y));
        ImGui::Dummy(ImVec2(totalW, 0));

        // Pool URL + Worker inputs inline next to toggle (pool mode only)
        if (s_pool_mode && soloMiningActive) {
            // Solo mining is active — show disabled message instead of inputs
            float inputFrameH = ImGui::GetFrameHeight();
            float vertOff = (toggleH - inputFrameH) * 0.5f;
            ImGui::SetCursorScreenPos(ImVec2(tMax.x + Layout::spacingLg(), tMin.y + vertOff));

            ImGui::PushStyleColor(ImGuiCol_Text, ImGui::ColorConvertU32ToFloat4(Warning()));
            ImGui::AlignTextToFramePadding();
            ImGui::PushFont(Type().iconSmall());
            ImGui::TextUnformatted(ICON_MD_INFO);
            ImGui::PopFont();
            ImGui::SameLine(0, Layout::spacingSm());
            ImGui::PushFont(capFont);
            ImGui::TextUnformatted(TR("mining_stop_solo_for_pool_settings"));
            ImGui::PopFont();
            ImGui::PopStyleColor();
        } else if (s_pool_mode) {
            // Position inputs to the right of the toggle
            float inputFrameH = ImGui::GetFrameHeight();
            float vertOff = (toggleH - inputFrameH) * 0.5f;
            float inputsStartX = tMax.x + Layout::spacingLg();
            ImGui::SetCursorScreenPos(ImVec2(inputsStartX, tMin.y + vertOff));

            // Manual vs Auto-balance pool selection. In Auto mode the wallet picks the
            // pool by hashrate (App::updatePoolAutoBalance), so the URL group is shown
            // disabled and mirrors the auto-selected pool.
            const bool autoMode = app->settings()->getPoolSelectMode()
                                  == config::Settings::PoolSelectMode::AutoBalance;
            if (autoMode) {
                const std::string cur = app->settings()->getPoolUrl();
                if (cur != s_pool_url) {
                    strncpy(s_pool_url, cur.c_str(), sizeof(s_pool_url) - 1);
                    s_pool_url[sizeof(s_pool_url) - 1] = '\0';
                }
            }
            ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 4.0f * dp);
            ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(8 * dp, 4 * dp));

            float inputFrameH2 = ImGui::GetFrameHeight();
            float iconBtnW = inputFrameH2;
            float resetBtnW = iconBtnW;
            float contentEndX = ImGui::GetWindowPos().x + ImGui::GetWindowContentRegionMax().x;
            // Each input group: [input][▼][bookmark]
            // Layout: [URL group] [spacing] [Worker group] [spacing] [reset]
            float perGroupExtra = iconBtnW * 2;  // dropdown + bookmark
            float remainW = contentEndX - inputsStartX - Layout::spacingSm() - resetBtnW
                            - Layout::spacingSm() - perGroupExtra * 2;
            // Floor keeps the inputs usable when cramped; the ceiling stops a
            // single input sprawling absurdly wide on a large window (leftover
            // space becomes right-side margin). Caps are logical px * dp.
            float urlW  = std::min(std::max(60.0f, remainW * 0.30f), 420.0f * dp);
            float wrkW  = std::min(std::max(40.0f, remainW * 0.70f), 560.0f * dp);

            // Track positions for popup alignment
            float urlGroupStartX = ImGui::GetCursorScreenPos().x;
            float urlGroupStartY = ImGui::GetCursorScreenPos().y;
            float urlGroupW = urlW + perGroupExtra;

            // === Pool URL input === (disabled in Auto mode — the wallet picks the pool)
            if (autoMode) ImGui::BeginDisabled();
            ImGui::SetNextItemWidth(urlW);
            if (ImGui::InputTextWithHint("##PoolURL", TR("mining_pool_url"), s_pool_url, sizeof(s_pool_url))) {
                s_pool_settings_dirty = true;
            }

            // --- URL: Dropdown arrow button ---
            ImGui::SameLine(0, 0);
            {
                material::IconButtonStyle st;
                st.color = OnSurfaceMedium();
                st.hoverBg = StateHover();
                st.bgRounding = 4.0f * dp;
                st.tooltip = TR("mining_saved_pools");
                if (material::IconButton("##PoolDropdown", ICON_MD_ARROW_DROP_DOWN, Type().iconSmall(),
                                         ImVec2(iconBtnW, inputFrameH2), st)) {
                    ImGui::OpenPopup("##SavedPoolsPopup");
                }
            }

            // --- URL: Bookmark button ---
            ImGui::SameLine(0, 0);
            {
                std::string currentUrl(s_pool_url);
                bool alreadySaved = miningValueAlreadySaved(app->settings()->getSavedPoolUrls(), currentUrl);
                material::IconButtonStyle st;
                st.color = alreadySaved ? Primary() : OnSurfaceMedium();
                st.hoverBg = StateHover();
                st.bgRounding = 4.0f * dp;
                st.tooltip = alreadySaved ? TR("mining_already_saved") : TR("mining_save_pool_url");
                if (material::IconButton("##SavePoolUrl", alreadySaved ? ICON_MD_BOOKMARK : ICON_MD_BOOKMARK_BORDER,
                                         Type().iconSmall(), ImVec2(iconBtnW, inputFrameH2), st)
                    && !currentUrl.empty() && !alreadySaved) {
                    app->settings()->addSavedPoolUrl(currentUrl);
                    app->settings()->save();
                }
            }

            // --- URL: Popup positioned below the input group ---
            // Match popup width to input group; zero horizontal padding so
            // item highlights are flush with the popup container edges.
            ImGui::SetNextWindowPos(ImVec2(urlGroupStartX, urlGroupStartY + inputFrameH2));
            ImGui::SetNextWindowSize(ImVec2(urlGroupW, 0));
            ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 4.0f * dp);
            ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 2 * dp));
            ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
            if (ImGui::BeginPopup("##SavedPoolsPopup")) {
                // Suggested (official) pools — one click to select, shown above the
                // user's saved favorites.
                {
                    const float sPopupInnerW = ImGui::GetContentRegionAvail().x;
                    const float sRowH = ImGui::GetFrameHeight();
                    const float sTextPadX = 8 * dp;
                    ImGui::SetCursorPosX(sTextPadX);
                    ImGui::PushFont(Type().caption());
                    ImGui::TextDisabled("%s", TR("mining_suggested_pools"));
                    ImGui::PopFont();
                    ImFont* sRowFont = ImGui::GetFont();
                    const float sRowFontSz = ImGui::GetFontSize();
                    for (const auto& kp : util::knownPools()) {
                        ImGui::PushID(kp.id.c_str());
                        ImVec2 rowMin = ImGui::GetCursorScreenPos();
                        ImVec2 rowMax(rowMin.x + sPopupInnerW, rowMin.y + sRowH);
                        ImGui::InvisibleButton("##sugg", ImVec2(sPopupInnerW, sRowH));
                        bool rowHov = ImGui::IsItemHovered();
                        bool rowClk = ImGui::IsItemClicked();
                        bool isCurrent = (std::string(s_pool_url) == kp.stratum);
                        ImDrawList* pdl = ImGui::GetWindowDrawList();
                        if (rowHov) pdl->AddRectFilled(rowMin, rowMax, StateHover());
                        float textY = rowMin.y + (sRowH - sRowFontSz) * 0.5f;
                        pdl->AddText(sRowFont, sRowFontSz, ImVec2(rowMin.x + sTextPadX, textY),
                                     isCurrent ? Primary() : OnSurface(), kp.stratum.c_str());
                        if (rowHov) {
                            ImGui::SetMouseCursor(ImGuiMouseCursor_Hand);
                            material::Tooltip("%s", kp.label.c_str());
                        }
                        if (rowClk) {
                            strncpy(s_pool_url, kp.stratum.c_str(), sizeof(s_pool_url) - 1);
                            s_pool_url[sizeof(s_pool_url) - 1] = '\0';
                            s_pool_settings_dirty = true;
                            ImGui::CloseCurrentPopup();
                        }
                        ImGui::PopID();
                    }
                    ImGui::Separator();
                }
                const auto& savedUrls = app->settings()->getSavedPoolUrls();
                if (savedUrls.empty()) {
                    ImGui::SetCursorPosX(8 * dp);
                    ImGui::PushFont(Type().caption());
                    ImGui::TextDisabled("%s", TR("mining_no_saved_pools"));
                    ImGui::PopFont();
                    ImGui::SetCursorPosX(8 * dp);
                    ImGui::PushFont(Type().caption());
                    ImGui::TextDisabled("%s", TR("mining_click"));
                    ImGui::PopFont();
                    ImGui::SameLine(0, 2 * dp);
                    ImGui::PushFont(Type().iconSmall());
                    ImGui::TextDisabled(ICON_MD_BOOKMARK_BORDER);
                    ImGui::PopFont();
                    ImGui::SameLine(0, 2 * dp);
                    ImGui::PushFont(Type().caption());
                    ImGui::TextDisabled("%s", TR("mining_to_save"));
                    ImGui::PopFont();
                } else {
                    std::string urlToRemove;
                    float popupInnerW = ImGui::GetContentRegionAvail().x;
                    float xZoneW = ImGui::GetFrameHeight();
                    float textPadX = 8 * dp;
                    ImFont* rowFont = ImGui::GetFont();
                    float rowFontSz = ImGui::GetFontSize();
                    float rowH = ImGui::GetFrameHeight();
                    int rowIdx = 0;
                    for (const auto& url : savedUrls) {
                        ImGui::PushID(url.c_str());
                        bool isCurrent = (std::string(s_pool_url) == url);
                        bool armed     = (s_armed_pool_idx == rowIdx);   // this row's X is arm-confirmed
                        ImVec2 rowMin = ImGui::GetCursorScreenPos();
                        ImVec2 rowMax(rowMin.x + popupInnerW, rowMin.y + rowH);
                        ImGui::InvisibleButton("##row", ImVec2(popupInnerW, rowH));
                        bool rowHov = ImGui::IsItemHovered();
                        bool rowClk = ImGui::IsItemClicked();
                        ImDrawList* pdl = ImGui::GetWindowDrawList();
                        bool inXZone = rowHov && ImGui::GetMousePos().x >= rowMax.x - xZoneW;
                        // Row background — flush with popup edges
                        if (isCurrent)
                            pdl->AddRectFilled(rowMin, rowMax, IM_COL32(255, 255, 255, 10));
                        if (rowHov && !inXZone)
                            pdl->AddRectFilled(rowMin, rowMax, StateHover());
                        // Item text with internal padding, middle-truncated so a long saved URL
                        // can't run under the trailing X (delete) button.
                        float textY = rowMin.y + (rowH - rowFontSz) * 0.5f;
                        float maxTextW = popupInnerW - xZoneW - textPadX * 2.0f;
                        std::string urlDisp = material::TruncateToWidth(url, rowFont, rowFontSz, maxTextW);
                        pdl->AddText(rowFont, rowFontSz,
                            ImVec2(rowMin.x + textPadX, textY),
                            isCurrent ? Primary() : OnSurface(), urlDisp.c_str());
                        // X (delete) button — flush with right edge, icon centered. First click on the X
                        // arms it (filled trash glyph + readable-error tint); a second click within the
                        // arm window actually removes. Armed row stays lit even when not hovered so the
                        // pending-delete state is visible.
                        {
                            ImVec2 xMin(rowMax.x - xZoneW, rowMin.y);
                            ImVec2 xMax(rowMax.x, rowMax.y);
                            if (inXZone) {
                                pdl->AddRectFilled(xMin, xMax, IM_COL32(255, 80, 80, 30));
                                ImGui::SetMouseCursor(ImGuiMouseCursor_Hand);
                                material::Tooltip("%s", armed ? TR("address_book_confirm_delete")
                                                              : TR("mining_remove"));
                            }
                            if (armed || inXZone || rowHov) {
                                ImFont* icoF = Type().iconSmall();
                                // Filled trash while armed reinforces the recolor; otherwise a plain X.
                                const char* xIcon = armed ? ICON_MD_DELETE : ICON_MD_CLOSE;
                                ImU32 xCol = armed ? ReadableError()
                                                   : (inXZone ? Error() : OnSurfaceDisabled());
                                ImVec2 iSz = icoF->CalcTextSizeA(icoF->LegacySize, FLT_MAX, 0, xIcon);
                                ImVec2 xCenter((xMin.x + xMax.x) * 0.5f, (xMin.y + xMax.y) * 0.5f);
                                pdl->AddText(icoF, icoF->LegacySize,
                                    ImVec2(xCenter.x - iSz.x * 0.5f, xCenter.y - iSz.y * 0.5f),
                                    xCol, xIcon);
                            }
                        }
                        // Hovering a *different* row's X disarms the previously armed one.
                        if (inXZone && !armed && s_armed_pool_idx >= 0)
                            s_armed_pool_idx = -1;
                        // Click handling
                        if (rowClk) {
                            if (inXZone) {
                                if (armed) {
                                    urlToRemove = url;            // 2nd click on the armed row removes
                                } else {
                                    s_armed_pool_idx  = rowIdx;   // 1st click arms this row
                                    s_armed_pool_time = nowTime;
                                }
                            } else {
                                s_armed_pool_idx = -1;            // selecting a row disarms
                                strncpy(s_pool_url, url.c_str(), sizeof(s_pool_url) - 1);
                                s_pool_url[sizeof(s_pool_url) - 1] = '\0';
                                s_pool_settings_dirty = true;
                                ImGui::CloseCurrentPopup();
                            }
                        }
                        if (rowHov && !inXZone)
                            ImGui::SetMouseCursor(ImGuiMouseCursor_Hand);
                        ImGui::PopID();
                        rowIdx++;
                    }
                    if (!urlToRemove.empty()) {
                        app->settings()->removeSavedPoolUrl(urlToRemove);
                        app->settings()->save();
                        s_armed_pool_idx = -1;   // removal shifts indices — drop the arm
                    }
                }
                ImGui::EndPopup();
            }
            ImGui::PopStyleVar(3);  // WindowRounding, WindowPadding, ItemSpacing for URL popup
            if (autoMode) ImGui::EndDisabled();
            ImGui::SameLine(0, Layout::spacingSm());
            float wrkGroupStartX = ImGui::GetCursorScreenPos().x;
            float wrkGroupStartY = ImGui::GetCursorScreenPos().y;
            float wrkGroupW = wrkW + perGroupExtra;

            ImGui::SetNextItemWidth(wrkW);
            if (ImGui::InputTextWithHint("##PoolWorker", TR("mining_payout_address"), s_pool_worker, sizeof(s_pool_worker))) {
                s_pool_settings_dirty = true;
            }
            if (ImGui::IsItemHovered()) {
                std::string currentWorkerStr(s_pool_worker);
                if (currentWorkerStr.empty()) {
                    material::Tooltip("%s", TR("mining_generate_z_address_hint"));
                } else if (currentWorkerStr != "x" && !util::isValidRecipientAddress(currentWorkerStr)) {
                    material::Tooltip("%s", TR("mining_payout_invalid"));   // block start below too (M-01)
                } else {
                    material::Tooltip("%s", TR("mining_payout_tooltip"));
                }
            }

            // --- Worker: Dropdown arrow button ---
            ImGui::SameLine(0, 0);
            {
                material::IconButtonStyle st;
                st.color = OnSurfaceMedium();
                st.hoverBg = StateHover();
                st.bgRounding = 4.0f * dp;
                st.tooltip = TR("mining_saved_addresses");
                if (material::IconButton("##WorkerDropdown", ICON_MD_ARROW_DROP_DOWN, Type().iconSmall(),
                                         ImVec2(iconBtnW, inputFrameH2), st)) {
                    ImGui::OpenPopup("##SavedWorkersPopup");
                }
            }

            // --- Worker: Bookmark button ---
            ImGui::SameLine(0, 0);
            {
                std::string currentWorker(s_pool_worker);
                bool alreadySaved = miningValueAlreadySaved(app->settings()->getSavedPoolWorkers(), currentWorker);
                material::IconButtonStyle st;
                st.color = alreadySaved ? Primary() : OnSurfaceMedium();
                st.hoverBg = StateHover();
                st.bgRounding = 4.0f * dp;
                st.tooltip = alreadySaved ? TR("mining_already_saved") : TR("mining_save_payout_address");
                if (material::IconButton("##SaveWorkerAddr", alreadySaved ? ICON_MD_BOOKMARK : ICON_MD_BOOKMARK_BORDER,
                                         Type().iconSmall(), ImVec2(iconBtnW, inputFrameH2), st)
                    && !currentWorker.empty() && currentWorker != "x" && !alreadySaved) {
                    app->settings()->addSavedPoolWorker(currentWorker);
                    app->settings()->save();
                }
            }

            // --- Worker: Popup positioned below the input group ---
            // Popup sized to fit full z-addresses without truncation;
            // zero horizontal padding so item highlights are flush with edges.
            // Wide enough for full z-addresses, but ceiling it so it doesn't span
            // the whole window on a large display (leftover -> unused margin).
            float addrPopupW = std::min(std::max(wrkGroupW, availWidth * 0.55f), 640.0f * dp);
            ImGui::SetNextWindowPos(ImVec2(wrkGroupStartX, wrkGroupStartY + inputFrameH2));
            ImGui::SetNextWindowSize(ImVec2(addrPopupW, 0));
            ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 4.0f * dp);
            ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 2 * dp));
            ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
            if (ImGui::BeginPopup("##SavedWorkersPopup")) {
                const auto& savedWorkers = app->settings()->getSavedPoolWorkers();
                if (savedWorkers.empty()) {
                    ImGui::SetCursorPosX(8 * dp);
                    ImGui::PushFont(Type().caption());
                    ImGui::TextDisabled("%s", TR("mining_no_saved_addresses"));
                    ImGui::PopFont();
                    ImGui::SetCursorPosX(8 * dp);
                    ImGui::PushFont(Type().caption());
                    ImGui::TextDisabled("%s", TR("mining_click"));
                    ImGui::PopFont();
                    ImGui::SameLine(0, 2 * dp);
                    ImGui::PushFont(Type().iconSmall());
                    ImGui::TextDisabled(ICON_MD_BOOKMARK_BORDER);
                    ImGui::PopFont();
                    ImGui::SameLine(0, 2 * dp);
                    ImGui::PushFont(Type().caption());
                    ImGui::TextDisabled("%s", TR("mining_to_save"));
                    ImGui::PopFont();
                } else {
                    std::string addrToRemove;
                    float wPopupInnerW = ImGui::GetContentRegionAvail().x;
                    float wXZoneW = ImGui::GetFrameHeight();
                    float wTextPadX = 8 * dp;
                    ImFont* wRowFont = ImGui::GetFont();
                    float wRowFontSz = ImGui::GetFontSize();
                    float wRowH = ImGui::GetFrameHeight();
                    int wRowIdx = 0;
                    for (const auto& addr : savedWorkers) {
                        ImGui::PushID(addr.c_str());
                        bool isCurrent = (std::string(s_pool_worker) == addr);
                        bool armed     = (s_armed_worker_idx == wRowIdx);   // this row's X is arm-confirmed
                        ImVec2 rowMin = ImGui::GetCursorScreenPos();
                        ImVec2 rowMax(rowMin.x + wPopupInnerW, rowMin.y + wRowH);
                        ImGui::InvisibleButton("##row", ImVec2(wPopupInnerW, wRowH));
                        bool rowHov = ImGui::IsItemHovered();
                        bool rowClk = ImGui::IsItemClicked();
                        ImDrawList* pdl = ImGui::GetWindowDrawList();
                        bool inXZone = rowHov && ImGui::GetMousePos().x >= rowMax.x - wXZoneW;
                        // Row background — flush with popup edges
                        if (isCurrent)
                            pdl->AddRectFilled(rowMin, rowMax, IM_COL32(255, 255, 255, 10));
                        if (rowHov && !inXZone)
                            pdl->AddRectFilled(rowMin, rowMax, StateHover());
                        // Address text with internal padding, middle-truncated so a full z-address
                        // (~78 chars) can't run under the trailing X (delete) button.
                        float textY = rowMin.y + (wRowH - wRowFontSz) * 0.5f;
                        float wMaxTextW = wPopupInnerW - wXZoneW - wTextPadX * 2.0f;
                        std::string addrDisp = material::TruncateToWidth(addr, wRowFont, wRowFontSz, wMaxTextW);
                        pdl->AddText(wRowFont, wRowFontSz,
                            ImVec2(rowMin.x + wTextPadX, textY),
                            isCurrent ? Primary() : OnSurface(), addrDisp.c_str());
                        // Tooltip for long addresses
                        if (rowHov && !inXZone)
                            material::Tooltip("%s", addr.c_str());
                        // X (delete) button — flush with right edge, icon centered. First click on the X
                        // arms it (filled trash glyph + readable-error tint); a second click within the
                        // arm window actually removes. Armed row stays lit even when not hovered so the
                        // pending-delete state is visible.
                        {
                            ImVec2 xMin(rowMax.x - wXZoneW, rowMin.y);
                            ImVec2 xMax(rowMax.x, rowMax.y);
                            if (inXZone) {
                                pdl->AddRectFilled(xMin, xMax, IM_COL32(255, 80, 80, 30));
                                ImGui::SetMouseCursor(ImGuiMouseCursor_Hand);
                                material::Tooltip("%s", armed ? TR("address_book_confirm_delete")
                                                              : TR("mining_remove"));
                            }
                            if (armed || inXZone || rowHov) {
                                ImFont* icoF = Type().iconSmall();
                                // Filled trash while armed reinforces the recolor; otherwise a plain X.
                                const char* xIcon = armed ? ICON_MD_DELETE : ICON_MD_CLOSE;
                                ImU32 xCol = armed ? ReadableError()
                                                   : (inXZone ? Error() : OnSurfaceDisabled());
                                ImVec2 iSz = icoF->CalcTextSizeA(icoF->LegacySize, FLT_MAX, 0, xIcon);
                                ImVec2 xCenter((xMin.x + xMax.x) * 0.5f, (xMin.y + xMax.y) * 0.5f);
                                pdl->AddText(icoF, icoF->LegacySize,
                                    ImVec2(xCenter.x - iSz.x * 0.5f, xCenter.y - iSz.y * 0.5f),
                                    xCol, xIcon);
                            }
                        }
                        // Hovering a *different* row's X disarms the previously armed one.
                        if (inXZone && !armed && s_armed_worker_idx >= 0)
                            s_armed_worker_idx = -1;
                        // Click handling
                        if (rowClk) {
                            if (inXZone) {
                                if (armed) {
                                    addrToRemove = addr;             // 2nd click on the armed row removes
                                } else {
                                    s_armed_worker_idx  = wRowIdx;   // 1st click arms this row
                                    s_armed_worker_time = nowTime;
                                }
                            } else {
                                s_armed_worker_idx = -1;             // selecting a row disarms
                                strncpy(s_pool_worker, addr.c_str(), sizeof(s_pool_worker) - 1);
                                s_pool_worker[sizeof(s_pool_worker) - 1] = '\0';
                                s_pool_settings_dirty = true;
                                ImGui::CloseCurrentPopup();
                            }
                        }
                        if (rowHov && !inXZone)
                            ImGui::SetMouseCursor(ImGuiMouseCursor_Hand);
                        ImGui::PopID();
                        wRowIdx++;
                    }
                    if (!addrToRemove.empty()) {
                        app->settings()->removeSavedPoolWorker(addrToRemove);
                        app->settings()->save();
                        s_armed_worker_idx = -1;   // removal shifts indices — drop the arm
                    }
                }
                ImGui::EndPopup();
            }
            ImGui::PopStyleVar(3);  // WindowRounding, WindowPadding, ItemSpacing for Worker popup

            // === Reset to defaults button ===
            ImGui::SameLine(0, Layout::spacingSm());
            {
                material::IconButtonStyle st;
                st.color = OnSurfaceMedium();
                st.hoverBg = StateHover();
                st.bgRounding = 4.0f * dp;
                st.tooltip = TR("mining_reset_defaults");
                if (material::IconButton("##ResetPoolDefaults", ICON_MD_REFRESH, Type().iconSmall(),
                                         ImVec2(inputFrameH2, inputFrameH2), st)) {
                    strncpy(s_pool_url, defaultPoolUrl(), sizeof(s_pool_url) - 1);
                    // Default to user's first shielded (z) address for pool payouts.
                    // Leave blank if no z-address exists yet.
                    std::string defaultAddr = defaultPoolWorkerAddress(state.addresses);
                    strncpy(s_pool_worker, defaultAddr.c_str(), sizeof(s_pool_worker) - 1);
                    s_pool_worker[sizeof(s_pool_worker) - 1] = '\0';
                    s_pool_settings_dirty = true;
                }
            }

            ImGui::PopStyleVar(2);
        }

        // Ensure cursor Y is at toggle bottom regardless of pool input widgets,
        // so the cards below stay at the same position in both solo and pool modes.
        ImGui::SetCursorScreenPos(ImVec2(tMin.x, tMax.y));
        ImGui::Dummy(ImVec2(0, gap * 0.5f));
}

} // namespace ui
} // namespace dragonx
