#include "engine_payment.h"

#include <curl/curl.h>
#include <iostream>
#include <sstream>
#include <iomanip>

namespace node669427 {

static std::string extract_json_field(const std::string& json, const std::string& key) {
    auto pos = json.find("\"" + key + "\"");
    if (pos == std::string::npos) return "";
    auto colon = json.find(':', pos);
    if (colon == std::string::npos) return "";
    auto start = json.find_first_of("\"", colon + 1);
    if (start == std::string::npos) {
        auto val_start = json.find_first_not_of(" \t", colon + 1);
        if (val_start == std::string::npos) return "";
        auto val_end = json.find_first_of(",}\r\n", val_start);
        if (val_end == std::string::npos) val_end = json.size();
        return json.substr(val_start, val_end - val_start);
    }
    auto end = json.find_first_of("\"", start + 1);
    if (end == std::string::npos) return "";
    return json.substr(start + 1, end - start - 1);
}

PaymentProcessor::PaymentProcessor(NodeConfig& config, VaultPtr vault, CryptoEngine& crypto)
    : config_(config), vault_(vault), crypto_(crypto) {}

size_t PaymentProcessor::curlWriteCb(void* contents, size_t size, size_t nmemb, std::string* userp) {
    userp->append((char*)contents, size * nmemb);
    return size * nmemb;
}

std::string PaymentProcessor::curlPost(const std::string& url, const std::string& body,
                                        const std::vector<std::string>& extra_headers) {
    CURL* curl = curl_easy_init();
    if (!curl) return "";
    std::string response;
    struct curl_slist* headers = curl_slist_append(nullptr, "Content-Type: application/json");
    for (const auto& h : extra_headers) {
        headers = curl_slist_append(headers, h.c_str());
    }
    curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, body.c_str());
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curlWriteCb);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
    curl_easy_setopt(curl, CURLOPT_TIMEOUT, 30L);
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L);
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2L);
    CURLcode res = curl_easy_perform(curl);
    curl_slist_free_all(headers);
    curl_easy_cleanup(curl);
    if (res != CURLE_OK) return "";
    return response;
}

std::string PaymentProcessor::generatePaymentId() {
    auto now = std::chrono::system_clock::now();
    auto ts = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count();
    std::string nonce = crypto_.generateNonce(8);
    std::ostringstream ss;
    ss << "pay-" << ts << "-" << nonce;
    return ss.str();
}

std::string PaymentProcessor::initiate(const std::string& body) {
    std::string method_str = extract_json_field(body, "method");
    PaymentMethod method = parseMethod(method_str);
    if (method == PaymentMethod::UNKNOWN) {
        return "{\"error\":\"invalid_payment_method\",\"method\":\"" + method_str + "\"}";
    }

    switch (method) {
        case PaymentMethod::STRIPE: return handleStripe(body);
        case PaymentMethod::XMR: return handleXMR(body);
        case PaymentMethod::USDT_TRC: return handleUSDTTRC(body);
        case PaymentMethod::USDC_POLY: return handleUSDCPoly(body);
        case PaymentMethod::ETRANSFER: return handleETransfer(body);
        default: return "{\"error\":\"unhandled_method\"}";
    }
}

static const char* methodToStr(PaymentMethod m) {
    switch (m) {
        case PaymentMethod::STRIPE: return "stripe";
        case PaymentMethod::XMR: return "xmr";
        case PaymentMethod::USDT_TRC: return "usdt-trc";
        case PaymentMethod::USDC_POLY: return "usdc-poly";
        case PaymentMethod::ETRANSFER: return "etransfer";
        default: return "unknown";
    }
}

std::string PaymentProcessor::status(const std::string& payment_id) {
    std::lock_guard<std::mutex> lock(records_mutex_);
    auto it = records_.find(payment_id);
    if (it == records_.end()) {
        return "{\"error\":\"payment_not_found\",\"id\":\"" + payment_id + "\"}";
    }
    std::ostringstream json;
    json << "{\"id\":\"" << it->second.id << "\""
         << ",\"method\":\"" << methodToStr(it->second.method) << "\""
         << ",\"status\":\"" << it->second.status << "\""
         << ",\"amount\":" << it->second.amount
         << ",\"currency\":\"" << it->second.currency << "\"}";
    return json.str();
}

std::string PaymentProcessor::cancel(const std::string& payment_id) {
    std::lock_guard<std::mutex> lock(records_mutex_);
    auto it = records_.find(payment_id);
    if (it == records_.end()) {
        return "{\"error\":\"payment_not_found\",\"id\":\"" + payment_id + "\"}";
    }
    it->second.status = "cancelled";
    it->second.updated = std::chrono::system_clock::now();
    return "{\"status\":\"cancelled\",\"id\":\"" + payment_id + "\"}";
}

std::string PaymentProcessor::handleStripe(const std::string& payload) {
    std::string amount = extract_json_field(payload, "amount");
    std::string currency = extract_json_field(payload, "currency");
    std::string api_key = vault_->get("stripe_api_key");
    if (api_key.empty()) {
        return "{\"error\":\"stripe_credentials_missing\"}";
    }

    std::string payment_id = generatePaymentId();
    double amt = 0.0;
    try { amt = std::stod(amount); } catch (...) {}

    {
        std::lock_guard<std::mutex> lock(records_mutex_);
        PaymentRecord rec;
        rec.id = payment_id;
        rec.method = PaymentMethod::STRIPE;
        rec.status = "pending";
        rec.amount = amt;
        rec.currency = currency.empty() ? "usd" : currency;
        rec.created = std::chrono::system_clock::now();
        rec.updated = rec.created;
        records_[payment_id] = rec;
    }

    std::string bridge_url = config_.services.stripe_bridge_url;
    if (!bridge_url.empty()) {
        std::string req_body = "{\"payment_id\":\"" + payment_id +
                               "\",\"amount\":\"" + amount +
                               "\",\"currency\":\"" + currency + "\"}";
        curlPost(bridge_url + "/charge", req_body, {});
    }

    return "{\"status\":\"pending\",\"payment_id\":\"" + payment_id +
           "\",\"method\":\"stripe\",\"amount\":" + amount +
           ",\"currency\":\"" + currency + "\"}";
}

std::string PaymentProcessor::handleXMR(const std::string& payload) {
    std::string amount = extract_json_field(payload, "amount");
    std::string wallet_url = config_.services.xmr_wallet_url;
    if (wallet_url.empty()) {
        return "{\"error\":\"xmr_wallet_not_configured\"}";
    }

    std::string payment_id = generatePaymentId();

    std::string rpc_body = "{\"jsonrpc\":\"2.0\",\"id\":\"" + payment_id +
                           "\",\"method\":\"create_address\",\"params\":{\"label\":\"" +
                           payment_id + "\"}}";
    std::string resp = curlPost(wallet_url, rpc_body, {});

    {
        std::lock_guard<std::mutex> lock(records_mutex_);
        PaymentRecord rec;
        rec.id = payment_id;
        rec.method = PaymentMethod::XMR;
        rec.status = "awaiting_payment";
        rec.amount = 0.0;
        try { rec.amount = std::stod(amount); } catch (...) {}
        rec.currency = "xmr";
        rec.created = std::chrono::system_clock::now();
        rec.updated = rec.created;
        records_[payment_id] = rec;
    }

    return "{\"status\":\"awaiting_payment\",\"payment_id\":\"" + payment_id +
           "\",\"method\":\"xmr\",\"wallet_response\":" + (resp.empty() ? "{}" : resp) + "}";
}

std::string PaymentProcessor::handleUSDTTRC(const std::string& payload) {
    std::string amount = extract_json_field(payload, "amount");
    std::string to_address = extract_json_field(payload, "to_address");
    std::string signer_url = config_.services.tron_signer_url;
    if (signer_url.empty()) {
        return "{\"error\":\"tron_signer_not_configured\"}";
    }

    std::string payment_id = generatePaymentId();

    std::string req_body = "{\"payment_id\":\"" + payment_id +
                           "\",\"amount\":\"" + amount +
                           "\",\"to\":\"" + to_address +
                           "\",\"token\":\"USDT\"}";
    std::string resp = curlPost(signer_url + "/transfer", req_body, {});

    {
        std::lock_guard<std::mutex> lock(records_mutex_);
        PaymentRecord rec;
        rec.id = payment_id;
        rec.method = PaymentMethod::USDT_TRC;
        rec.status = "pending";
        rec.amount = 0.0;
        try { rec.amount = std::stod(amount); } catch (...) {}
        rec.currency = "usdt-trc";
        rec.created = std::chrono::system_clock::now();
        rec.updated = rec.created;
        records_[payment_id] = rec;
    }

    return "{\"status\":\"pending\",\"payment_id\":\"" + payment_id +
           "\",\"method\":\"usdt-trc\",\"signer_response\":" + (resp.empty() ? "{}" : resp) + "}";
}

std::string PaymentProcessor::handleUSDCPoly(const std::string& payload) {
    std::string amount = extract_json_field(payload, "amount");
    std::string to_address = extract_json_field(payload, "to_address");
    std::string signer_url = config_.services.tron_signer_url;
    if (signer_url.empty()) {
        return "{\"error\":\"tron_signer_not_configured\"}";
    }

    std::string payment_id = generatePaymentId();

    std::string req_body = "{\"payment_id\":\"" + payment_id +
                           "\",\"amount\":\"" + amount +
                           "\",\"to\":\"" + to_address +
                           "\",\"token\":\"USDC\"}";
    std::string resp = curlPost(signer_url + "/transfer", req_body, {});

    {
        std::lock_guard<std::mutex> lock(records_mutex_);
        PaymentRecord rec;
        rec.id = payment_id;
        rec.method = PaymentMethod::USDC_POLY;
        rec.status = "pending";
        rec.amount = 0.0;
        try { rec.amount = std::stod(amount); } catch (...) {}
        rec.currency = "usdc-poly";
        rec.created = std::chrono::system_clock::now();
        rec.updated = rec.created;
        records_[payment_id] = rec;
    }

    return "{\"status\":\"pending\",\"payment_id\":\"" + payment_id +
           "\",\"method\":\"usdc-poly\",\"signer_response\":" + (resp.empty() ? "{}" : resp) + "}";
}

std::string PaymentProcessor::handleETransfer(const std::string& payload) {
    std::string amount = extract_json_field(payload, "amount");
    std::string email = extract_json_field(payload, "email");
    std::string payment_id = generatePaymentId();

    {
        std::lock_guard<std::mutex> lock(records_mutex_);
        PaymentRecord rec;
        rec.id = payment_id;
        rec.method = PaymentMethod::ETRANSFER;
        rec.status = "pending_verification";
        rec.amount = 0.0;
        try { rec.amount = std::stod(amount); } catch (...) {}
        rec.currency = "cad";
        rec.metadata = "{\"email\":\"" + email + "\"}";
        rec.created = std::chrono::system_clock::now();
        rec.updated = rec.created;
        records_[payment_id] = rec;
    }

    return "{\"status\":\"pending_verification\",\"payment_id\":\"" + payment_id +
           "\",\"method\":\"etransfer\",\"amount\":\"" + amount +
           "\",\"currency\":\"cad\"}";
}

} // namespace node669427
