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

#include "import_key_dialog.h"
#include "../../app.h"
#include "../../rpc/rpc_client.h"
#include "../../rpc/rpc_worker.h"
#include "../../util/i18n.h"
#include "../notifications.h"
#include "../schema/ui_schema.h"
#include "../material/draw_helpers.h"
#include "../material/type.h"
#include "../../embedded/IconsMaterialDesign.h"
#include "imgui.h"

#include <string>
#include <vector>
#include <sstream>

namespace dragonx {
namespace ui {

using json = nlohmann::json;

// Static state
static bool s_open = false;
static char s_key_input[4096] = "";
static bool s_rescan = true;
static int s_rescan_height = 0;  // 0 = full rescan
static bool s_importing = false;
static std::string s_status;
static int s_total_keys = 0;
static int s_imported_keys = 0;
static int s_failed_keys = 0;
static bool s_paste_previewing = false;
static std::string s_preview_text;

// Helper to detect key type
static std::string detectKeyType(const std::string& key)
{
    if (key.empty()) return "unknown";
    
    // Z-address spending keys start with "secret-extended-key-" or "SK" prefix patterns
    if (key.substr(0, 20) == "secret-extended-key-") {
        return "z-spending";
    }
    
    // Legacy z-addr keys (SK prefix)
    if (key.length() >= 2 && key[0] == 'S' && key[1] == 'K') {
        return "z-spending";
    }
    
    // T-address private keys (WIF format) - start with 5, K, or L for Bitcoin-derived
    // DragonX/HUSH uses different prefixes
    if (key.length() >= 51 && key.length() <= 52) {
        char first = key[0];
        if (first == '5' || first == 'K' || first == 'L' || first == 'U') {
            return "t-privkey";
        }
    }
    
    return "unknown";
}

// Helper to split input into individual keys
static std::vector<std::string> splitKeys(const std::string& input)
{
    std::vector<std::string> keys;
    std::istringstream stream(input);
    std::string line;
    
    while (std::getline(stream, line)) {
        // Trim whitespace
        size_t start = line.find_first_not_of(" \t\r\n");
        size_t end = line.find_last_not_of(" \t\r\n");
        
        if (start != std::string::npos && end != std::string::npos) {
            std::string key = line.substr(start, end - start + 1);
            if (!key.empty() && key[0] != '#') {  // Skip comments
                keys.push_back(key);
            }
        }
    }
    
    return keys;
}

void ImportKeyDialog::show()
{
    s_open = true;
    s_key_input[0] = '\0';
    s_rescan = true;
    s_rescan_height = 0;
    s_importing = false;
    s_status.clear();
    s_total_keys = 0;
    s_imported_keys = 0;
    s_failed_keys = 0;
    s_paste_previewing = false;
    s_preview_text.clear();
}

bool ImportKeyDialog::isOpen()
{
    return s_open;
}

void ImportKeyDialog::render(App* app)
{
    if (!s_open) return;

    auto& S = schema::UI();
    auto win = S.window("dialogs.import-key");
    auto keyInput = S.input("dialogs.import-key", "key-input");
    auto rescanInput = S.input("dialogs.import-key", "rescan-height-input");
    auto importBtn = S.button("dialogs.import-key", "import-button");
    auto closeBtn = S.button("dialogs.import-key", "close-button");

    if (material::BeginOverlayDialog(TR("import_key_title"), &s_open, win.width, 0.94f)) {
        // Warning
        ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.8f, 0.0f, 1.0f));
        ImGui::PushFont(material::Type().iconSmall());
        ImGui::Text(ICON_MD_WARNING);
        ImGui::PopFont();
        ImGui::SameLine(0, 4.0f);
        ImGui::TextWrapped("%s", TR("import_key_warning"));
        ImGui::PopStyleColor();
        
        ImGui::Spacing();
        ImGui::Separator();
        ImGui::Spacing();
        
        // Key input
        ImGui::Text("%s", TR("import_key_label"));
        ImGui::SameLine();
        ImGui::TextDisabled("(?)");
        if (ImGui::IsItemHovered()) {
            ImGui::SetTooltip("%s", TR("import_key_tooltip"));
        }

        // Validation indicator inline with title — check preview text during hover,
        // otherwise check the actual input
        {
            const char* checkSrc = s_key_input;
            if (s_paste_previewing && !s_preview_text.empty())
                checkSrc = s_preview_text.c_str();
            if (checkSrc[0] != '\0') {
                auto previewKeys = splitKeys(checkSrc);
                int pz = 0, pt = 0, pu = 0;
                for (const auto& k : previewKeys) {
                    std::string kt = detectKeyType(k);
                    if (kt == "z-spending") pz++;
                    else if (kt == "t-privkey") pt++;
                    else pu++;
                }
                if (pz > 0 || pt > 0) {
                    ImGui::SameLine();
                    char vbuf[128];
                    if (pz > 0 && pt > 0)
                        snprintf(vbuf, sizeof(vbuf), "%d shielded, %d transparent", pz, pt);
                    else if (pz > 0)
                        snprintf(vbuf, sizeof(vbuf), "%d shielded key(s)", pz);
                    else
                        snprintf(vbuf, sizeof(vbuf), "%d transparent key(s)", pt);
                    material::Type().textColored(material::TypeStyle::Caption, material::Success(), vbuf);
                    if (pu > 0) {
                        ImGui::SameLine();
                        snprintf(vbuf, sizeof(vbuf), "(%d unrecognized)", pu);
                        material::Type().textColored(material::TypeStyle::Caption, material::Error(), vbuf);
                    }
                } else if (pu > 0 && !s_paste_previewing) {
                    ImGui::SameLine();
                    material::Type().textColored(material::TypeStyle::Caption, material::Error(), "Unrecognized key format");
                }
            }
        }
        
        if (s_importing) {
            ImGui::BeginDisabled();
        }
        
        ImGui::SetNextItemWidth(-1);
        ImGui::InputTextMultiline("##KeyInput", s_key_input, sizeof(s_key_input),
                                  ImVec2(-1, keyInput.height > 0 ? keyInput.height : 150), ImGuiInputTextFlags_AllowTabInput);
        ImVec2 inputMin = ImGui::GetItemRectMin();
        ImVec2 inputMax = ImGui::GetItemRectMax();
        
        // Detect paste button hover before drawing it
        ImVec2 pasteBtnPos = ImGui::GetCursorScreenPos();
        // Estimate button size for hover detection
        ImFont* btnFont = S.resolveFont(importBtn.font);
        ImVec2 pasteBtnSize = btnFont
            ? ImVec2(btnFont->CalcTextSizeA(btnFont->LegacySize, FLT_MAX, 0, TR("paste_from_clipboard")).x
                     + ImGui::GetStyle().FramePadding.x * 2,
                     ImGui::GetFrameHeight())
            : ImVec2(150, ImGui::GetFrameHeight());
        bool paste_hovered = material::IsRectHovered(pasteBtnPos,
            ImVec2(pasteBtnPos.x + pasteBtnSize.x, pasteBtnPos.y + pasteBtnSize.y));

        // Handle preview state
        if (paste_hovered && !s_paste_previewing) {
            const char* clip = ImGui::GetClipboardText();
            if (clip && clip[0] != '\0') {
                std::string trimmed(clip);
                while (!trimmed.empty() && (trimmed.front() == ' ' || trimmed.front() == '\t' ||
                       trimmed.front() == '\n' || trimmed.front() == '\r'))
                    trimmed.erase(trimmed.begin());
                while (!trimmed.empty() && (trimmed.back() == ' ' || trimmed.back() == '\t' ||
                       trimmed.back() == '\n' || trimmed.back() == '\r'))
                    trimmed.pop_back();
                if (!trimmed.empty() && s_key_input[0] == '\0') {
                    s_preview_text = trimmed;
                    s_paste_previewing = true;
                }
            }
        } else if (!paste_hovered && s_paste_previewing) {
            s_paste_previewing = false;
            s_preview_text.clear();
        }

        // Draw transparent preview text overlay on the input field
        if (s_paste_previewing && !s_preview_text.empty()) {
            ImVec2 textPos(inputMin.x + ImGui::GetStyle().FramePadding.x,
                           inputMin.y + ImGui::GetStyle().FramePadding.y);
            ImVec4 previewCol = ImGui::GetStyleColorVec4(ImGuiCol_Text);
            previewCol.w = S.drawElement("dialogs.import-key", "paste-preview-alpha").sizeOr(0.3f);
            size_t maxChars = (size_t)S.drawElement("dialogs.import-key", "paste-preview-max-chars").sizeOr(200.0f);
            // Clip to input rect
            ImGui::GetWindowDrawList()->PushClipRect(inputMin, inputMax, true);
            ImGui::GetWindowDrawList()->AddText(textPos, ImGui::ColorConvertFloat4ToU32(previewCol),
                s_preview_text.c_str(), s_preview_text.c_str() + std::min(s_preview_text.size(), maxChars));
            ImGui::GetWindowDrawList()->PopClipRect();
        }

        // Paste button
        if (material::StyledButton(TR("paste_from_clipboard"), ImVec2(0,0), S.resolveFont(importBtn.font))) {
            if (s_paste_previewing) {
                snprintf(s_key_input, sizeof(s_key_input), "%s", s_preview_text.c_str());
                s_paste_previewing = false;
                s_preview_text.clear();
            } else {
                const char* clipboard = ImGui::GetClipboardText();
                if (clipboard) {
                    std::string trimmed(clipboard);
                    while (!trimmed.empty() && (trimmed.front() == ' ' || trimmed.front() == '\t' ||
                           trimmed.front() == '\n' || trimmed.front() == '\r'))
                        trimmed.erase(trimmed.begin());
                    while (!trimmed.empty() && (trimmed.back() == ' ' || trimmed.back() == '\t' ||
                           trimmed.back() == '\n' || trimmed.back() == '\r'))
                        trimmed.pop_back();
                    snprintf(s_key_input, sizeof(s_key_input), "%s", trimmed.c_str());
                }
            }
        }
        
        ImGui::SameLine();
        if (material::StyledButton(TR("clear"), ImVec2(0,0), S.resolveFont(importBtn.font))) {
            s_key_input[0] = '\0';
            s_paste_previewing = false;
            s_preview_text.clear();
        }
        
        ImGui::Spacing();
        
        // Rescan options
        ImGui::Checkbox(TR("import_key_rescan"), &s_rescan);
        
        if (s_rescan) {
            ImGui::Indent();
            ImGui::Text("%s", TR("import_key_start_height"));
            ImGui::SameLine();
            ImGui::SetNextItemWidth(rescanInput.width);
            ImGui::InputInt("##RescanHeight", &s_rescan_height);
            if (s_rescan_height < 0) s_rescan_height = 0;
            ImGui::SameLine();
            ImGui::TextDisabled("%s", TR("import_key_full_rescan"));
            ImGui::Unindent();
        }
        
        if (s_importing) {
            ImGui::EndDisabled();
        }
        
        ImGui::Spacing();
        ImGui::Separator();
        ImGui::Spacing();
        
        // Import button
        if (s_importing) {
            ImGui::BeginDisabled();
        }
        
        if (material::StyledButton(TR("import_key_btn"), ImVec2(importBtn.width, 0), S.resolveFont(importBtn.font))) {
            auto keys = splitKeys(s_key_input);
            
            if (keys.empty()) {
                Notifications::instance().warning(TR("import_key_no_valid"));
            } else if (!app->rpc() || !app->rpc()->isConnected()) {
                Notifications::instance().error(TR("not_connected"));
            } else {
                s_importing = true;
                s_total_keys = static_cast<int>(keys.size());
                s_imported_keys = 0;
                s_failed_keys = 0;
                s_status = "Importing...";
                
                // Import keys on worker thread to avoid freezing UI
                bool rescan = s_rescan;
                int rescanHeight = s_rescan_height;
                if (app->worker()) {
                    app->worker()->post([app, rpc = app->rpc(), keys, rescan, rescanHeight]() -> rpc::RPCWorker::MainCb {
                        int imported = 0;
                        int failed = 0;
                        
                        for (const auto& key : keys) {
                            std::string keyType = detectKeyType(key);
                            
                            try {
                                rpc::RPCClient::TraceScope trace("Settings / Import private keys");
                                if (keyType == "z-spending") {
                                    // z_importkey "key" "yes"|"no" startheight
                                    if (rescan && rescanHeight > 0) {
                                        rpc->call("z_importkey", {key, "yes", rescanHeight});
                                    } else {
                                        rpc->call("z_importkey", {key, rescan ? "yes" : "no"});
                                    }
                                    imported++;
                                } else if (keyType == "t-privkey") {
                                    // importprivkey does not accept a startheight;
                                    // import without rescan, then rescanblockchain
                                    // from the requested height afterward.
                                    if (rescan && rescanHeight > 0) {
                                        rpc->call("importprivkey", {key, "", false});
                                    } else {
                                        rpc->call("importprivkey", {key, "", rescan});
                                    }
                                    imported++;
                                } else {
                                    failed++;
                                }
                            } catch (...) {
                                failed++;
                            }
                        }

                        // If t-keys were imported without rescan (because a
                        // specific start height was requested), trigger a
                        // single rescanblockchain from that height now.
                        if (rescan && rescanHeight > 0 && imported > 0) {
                            try {
                                rpc::RPCClient::TraceScope trace("Settings / Import private keys");
                                rpc->call("rescanblockchain", {rescanHeight});
                            } catch (...) {
                                // rescan failure is non-fatal; user can retry
                            }
                        }
                        
                        return [app, imported, failed]() {
                            s_imported_keys = imported;
                            s_failed_keys = failed;
                            s_importing = false;
                            char buf[128];
                            snprintf(buf, sizeof(buf), "Import complete: %d success, %d failed",
                                    imported, failed);
                            s_status = buf;
                            if (imported > 0) {
                                app->invalidateAddressValidationCache();
                                app->refreshNow();
                                Notifications::instance().success(TR("import_key_success"), 5.0f);
                            }
                        };
                    });
                }
            }
        }
        
        if (s_importing) {
            ImGui::EndDisabled();
            ImGui::SameLine();
            ImGui::TextDisabled(TR("import_key_progress"), s_imported_keys + s_failed_keys, s_total_keys);
        }
        
        ImGui::SameLine();
        if (material::StyledButton(TR("close"), ImVec2(closeBtn.width, 0), S.resolveFont(closeBtn.font))) {
            s_open = false;
        }
        
        // Status
        if (!s_status.empty()) {
            ImGui::Spacing();
            bool success = s_failed_keys == 0 && !s_importing;
            ImGui::TextColored(
                success ? ImVec4(0.2f, 0.8f, 0.2f, 1.0f) : ImVec4(1.0f, 0.8f, 0.0f, 1.0f),
                "%s", s_status.c_str()
            );
        }
        
        ImGui::Spacing();
        ImGui::Separator();
        ImGui::Spacing();
        
        // Help text
        ImGui::TextDisabled("%s", TR("import_key_formats"));
        ImGui::BulletText("%s", TR("import_key_z_format"));
        ImGui::BulletText("%s", TR("import_key_t_format"));
        material::EndOverlayDialog();
    }
}

} // namespace ui
} // namespace dragonx
