#include "engine_artifact.h"

#include <iostream>
#include <sstream>
#include <chrono>
#include <thread>
#include <condition_variable>

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);
}

ArtifactProcessor::ArtifactProcessor(NodeConfig& config, CryptoEngine& crypto, VaultPtr vault,
                                     SecurityEngine& security, PaymentProcessor& payments,
                                     EmailDispatcher& email, FulfillmentEngine& fulfillment)
    : config_(config), crypto_(crypto), vault_(vault), security_(security),
      payments_(payments), email_(email), fulfillment_(fulfillment) {}

Artifact ArtifactProcessor::parseArtifact(const std::string& body) {
    Artifact art;
    art.signal_type = extract_json_field(body, "signal_type");
    art.payload = extract_json_field(body, "payload");
    art.source_node = extract_json_field(body, "source_node");
    art.timestamp = extract_json_field(body, "timestamp");
    art.hmac_signature = extract_json_field(body, "hmac_signature");
    if (art.timestamp.empty()) {
        auto now = std::chrono::system_clock::now();
        auto t = std::chrono::system_clock::to_time_t(now);
        char buf[64];
        std::strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%SZ", std::gmtime(&t));
        art.timestamp = buf;
    }
    return art;
}

std::string ArtifactProcessor::process(const std::string& body) {
    Artifact art = parseArtifact(body);
    if (art.signal_type.empty()) {
        return "{\"error\":\"missing_signal_type\"}";
    }

    {
        std::lock_guard<std::mutex> lock(queue_mutex_);
        queue_.push(art);
    }
    condition_.notify_one();

    std::string result = routeSignal(art);

    {
        std::lock_guard<std::mutex> lock(stats_mutex_);
        processed_count_++;
    }

    return result;
}

std::string ArtifactProcessor::routeSignal(const Artifact& art) {
    SignalType sig = parseSignal(art.signal_type);
    switch (sig) {
        case SignalType::PAYMENT_INIT: return handlePaymentInit(art);
        case SignalType::PAYMENT_STATUS: return handlePaymentStatus(art);
        case SignalType::PAYMENT_CANCEL: return handlePaymentCancel(art);
        case SignalType::EMAIL_PURCHASE: return handleEmailPurchase(art);
        case SignalType::EMAIL_BULK: return handleEmailBulk(art);
        case SignalType::FULFILLMENT_START: return handleFulfillmentStart(art);
        case SignalType::SECURITY_EVENT: return handleSecurityEvent(art);
        case SignalType::HEALTH_CHECK: return handleHealthCheck(art);
        case SignalType::WAF_UPDATE: return handleWafUpdate(art);
        case SignalType::DNS_ROTATE: return handleDnsRotate(art);
        default: return "{\"error\":\"unknown_signal\",\"signal\":\"" + art.signal_type + "\"}";
    }
}

std::string ArtifactProcessor::handlePaymentInit(const Artifact& art) {
    return payments_.initiate(art.payload);
}

std::string ArtifactProcessor::handlePaymentStatus(const Artifact& art) {
    std::string payment_id = extract_json_field(art.payload, "payment_id");
    return payments_.status(payment_id);
}

std::string ArtifactProcessor::handlePaymentCancel(const Artifact& art) {
    std::string payment_id = extract_json_field(art.payload, "payment_id");
    return payments_.cancel(payment_id);
}

std::string ArtifactProcessor::handleEmailPurchase(const Artifact& art) {
    return email_.dispatch(art.payload);
}

std::string ArtifactProcessor::handleEmailBulk(const Artifact& art) {
    return "{\"status\":\"queued\",\"signal\":\"EMAIL_BULK\",\"count\":0}";
}

std::string ArtifactProcessor::handleFulfillmentStart(const Artifact& art) {
    return fulfillment_.start(art.payload);
}

std::string ArtifactProcessor::handleSecurityEvent(const Artifact& art) {
    std::string event_type = extract_json_field(art.payload, "event_type");
    std::string source_ip = extract_json_field(art.payload, "source_ip");
    std::string severity = extract_json_field(art.payload, "severity");
    security_.logEvent(event_type, source_ip, severity);
    return "{\"status\":\"logged\",\"event_type\":\"" + event_type + "\"}";
}

std::string ArtifactProcessor::handleHealthCheck(const Artifact& art) {
    return "{\"status\":\"ok\",\"node\":\"" + config_.node_id +
           "\",\"signal\":\"HEALTH_CHECK\",\"timestamp\":\"" + art.timestamp + "\"}";
}

std::string ArtifactProcessor::handleWafUpdate(const Artifact& art) {
    std::string rules = extract_json_field(art.payload, "rules");
    return "{\"status\":\"queued\",\"signal\":\"WAF_UPDATE\",\"rules_size\":" + std::to_string(rules.size()) + "}";
}

std::string ArtifactProcessor::handleDnsRotate(const Artifact& art) {
    std::string domain = extract_json_field(art.payload, "domain");
    return "{\"status\":\"executed\",\"signal\":\"DNS_ROTATE\",\"domain\":\"" + domain + "\"}";
}

void ArtifactProcessor::run() {
    while (running_.load() && config_.running.load()) {
        std::unique_lock<std::mutex> lock(queue_mutex_);
        condition_.wait_for(lock, std::chrono::seconds(1), [this]() { return !queue_.empty() || !running_.load(); });
        if (!running_.load()) break;
    }
}

void ArtifactProcessor::stop() {
    running_.store(false);
    condition_.notify_all();
}

} // namespace node669427
