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

#include "export_transactions_dialog.h"
#include "../../app.h"
#include "../../util/i18n.h"
#include "../../util/platform.h"
#include "../notifications.h"
#include "../schema/ui_schema.h"
#include "../material/draw_helpers.h"
#include "../material/type.h"
#include "../widgets/copy_field.h"
#include "../theme.h"
#include "../../embedded/IconsMaterialDesign.h"
#include "imgui.h"

#include <string>
#include <fstream>
#include <sstream>
#include <ctime>
#include <iomanip>

namespace dragonx {
namespace ui {

// Static state
static bool s_open = false;
static char s_filename[256] = "";
static std::string s_saved_path;   // full path on success (shown as a copy field); empty otherwise
static std::string s_error;        // error message on failure; empty otherwise
// Re-entrancy guard: true while a CSV write is in flight (disables the
// Export button so a second synchronous write can't be kicked off).
static bool s_exporting = false;

// Helper to escape CSV field
static std::string escapeCSV(const std::string& field)
{
    // Neutralize spreadsheet formula injection: a field beginning with '=', '+', '-', '@',
    // tab, or CR is interpreted as a formula by Excel/LibreOffice, letting an attacker-supplied
    // memo/address execute on open. Prefix such fields with a single quote so they render as text.
    std::string safe = field;
    if (!safe.empty()) {
        const char c0 = safe.front();
        if (c0 == '=' || c0 == '+' || c0 == '-' || c0 == '@' || c0 == '\t' || c0 == '\r')
            safe.insert(safe.begin(), '\'');
    }
    if (safe.find(',') != std::string::npos ||
        safe.find('"') != std::string::npos ||
        safe.find('\n') != std::string::npos) {
        // Escape quotes and wrap in quotes
        std::string escaped;
        escaped.reserve(safe.size() + 4);
        escaped += '"';
        for (char c : safe) {
            if (c == '"') escaped += "\"\"";
            else escaped += c;
        }
        escaped += '"';
        return escaped;
    }
    return safe;
}

void ExportTransactionsDialog::show()
{
    s_open = true;
    s_saved_path.clear();
    s_error.clear();

    // Generate default filename with timestamp
    std::time_t now = std::time(nullptr);
    char timebuf[32];
    std::strftime(timebuf, sizeof(timebuf), "%Y%m%d_%H%M%S", std::localtime(&now));
    snprintf(s_filename, sizeof(s_filename), "dragonx_transactions_%s.csv", timebuf);
}

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

void ExportTransactionsDialog::hide()
{
    s_open = false;
    s_saved_path.clear();
    s_error.clear();
}

void ExportTransactionsDialog::render(App* app)
{
    if (!s_open) return;
    namespace m = material;

    m::OverlayDialogSpec ov;
    ov.title     = TR("export_tx_title");
    ov.p_open    = &s_open;
    ov.style     = m::OverlayStyle::BlurFloat;
    ov.cardWidth = 520.0f;
    ov.idSuffix  = "exporttx";
    if (!m::BeginOverlayDialog(ov)) return;

    const auto& state = app->getWalletState();

    ImGui::Text(TR("export_tx_count"), state.transactions.size());
    ImGui::Spacing();

    // Filename + save-location hint.
    m::LabeledInput(TR("output_filename"), "##Filename", s_filename, sizeof(s_filename));
    ImGui::Spacing();
    ImGui::TextColored(ImGui::ColorConvertU32ToFloat4(m::OnSurfaceDisabled()), "%s", TR("file_save_location"));

    // Result — success shows the saved path as a copy field; failure shows a red line.
    if (!s_saved_path.empty()) {
        ImGui::Spacing();
        ImGui::PushFont(m::Type().iconSmall());
        ImGui::TextColored(m::SuccessVec4(), ICON_MD_CHECK_CIRCLE);
        ImGui::PopFont();
        ImGui::SameLine(0, 4.0f * Layout::dpiScale());
        ImGui::TextColored(m::SuccessVec4(), "%s", TR("export_tx_success"));
        widgets::AddressCopyField("##exportedpath", s_saved_path);
    } else if (!s_error.empty()) {
        ImGui::Spacing();
        ImGui::PushTextWrapPos(0.0f);
        ImGui::TextColored(ImVec4(0.8f, 0.3f, 0.3f, 1.0f), "%s", s_error.c_str());
        ImGui::PopTextWrapPos();
    }

    ImGui::Spacing();

    bool doExport = false, doClose = false;
    m::DialogActionFooter(TR("export"), !s_exporting, TR("close"), doExport, doClose);
    if (doClose) s_open = false;
    if (doExport) {
        s_saved_path.clear();
        s_error.clear();
        if (state.transactions.empty()) {
            Notifications::instance().warning(TR("export_tx_none"));
        } else {
            s_exporting = true;
            std::string configDir = util::Platform::getConfigDir();
            std::string filepath = configDir + "/" + s_filename;

            std::ofstream file(filepath);
            if (!file.is_open()) {
                s_error = TR("export_tx_file_fail");
                Notifications::instance().error(TR("export_tx_file_fail"));
            } else {
                file << "Date,Type,Amount,Address,TXID,Confirmations,Memo\n";
                for (const auto& tx : state.transactions) {
                    std::time_t t = static_cast<std::time_t>(tx.timestamp);
                    char datebuf[32];
                    std::strftime(datebuf, sizeof(datebuf), "%Y-%m-%d %H:%M:%S", std::localtime(&t));
                    file << datebuf << ",";
                    file << escapeCSV(tx.type) << ",";
                    std::ostringstream amt;
                    amt << std::fixed << std::setprecision(8) << tx.amount;
                    file << amt.str() << ",";
                    file << escapeCSV(tx.address) << ",";
                    file << escapeCSV(tx.txid) << ",";
                    file << tx.confirmations << ",";
                    file << escapeCSV(tx.memo) << "\n";
                }
                file.close();
                s_saved_path = filepath;
                Notifications::instance().success(TR("export_tx_success"), 5.0f);
            }
            s_exporting = false;
        }
    }

    m::EndOverlayDialog();
}

} // namespace ui
} // namespace dragonx
