#pragma once
// engine_subsystems.h — Modular subsystem manager declarations
// Ported from v1-monolithic/include/engine.hpp → Iter2 modular architecture
// All manager classes: HbMgr, WdMgr, DdMon, FoMgr, ScMgr, FwMgr, LdMgr

#include "engine_config.h"

#include <cstdint>
#include <string>
#include <vector>
#include <queue>
#include <mutex>
#include <atomic>
#include <thread>
#include <condition_variable>
#include <memory>
#include <chrono>
#include <iostream>
#include <sstream>
#include <iomanip>
#include <unordered_set>
#include <unordered_map>
#include <functional>
#include <future>
#include <algorithm>
#include <cstring>
#include <cstdio>

// Forward declarations — avoid pulling in full headers
namespace node669427 {
    class CryptoEngine;
}
class OriginBridge;

// ──────────────────────────────────────────────────────────────
// Enums and types from v1 common.hpp, scoped for subsystems
// ──────────────────────────────────────────────────────────────

namespace node669427 {
namespace subsys {

// -- Path constants (compile-time, overridable) ----------------
#ifndef E_VERSION
#define E_VERSION "4.0.0"
#endif
#ifndef E_FAKE
#define E_FAKE "systemd-nscd"
#endif
#ifndef E_BASE
#define E_BASE "/opt/sysc/engine"
#endif
#ifndef E_KEYS
#define E_KEYS "/var/lib/sysc-engine"
#endif
#ifndef E_PID
#define E_PID "/run/sysc-engine/sysd-engine.pid"
#endif
#ifndef E_CFG
#define E_CFG E_BASE "/config/engine.json"
#endif
#ifndef E_SCRIPTS
#define E_SCRIPTS E_BASE "/scripts"
#endif
#ifndef E_SCRIPTS_ENC
#define E_SCRIPTS_ENC E_BASE "/scripts/.enc"
#endif
#ifndef E_WATCH
#define E_WATCH E_BASE "/watch"
#endif

// -- Logging macro (matches v1 LOG; uses syslog if available, else cerr) --
#if __has_include(<syslog.h>)
#include <syslog.h>
#endif

enum class LogLevel : uint8_t { DEBUG = 0, INFO = 1, WARN = 2, ERROR = 3, FATAL = 4 };

class Logger {
    static LogLevel& level() { static LogLevel l = LogLevel::INFO; return l; }
#if __has_include(<syslog.h>)
    static constexpr int lvl_to_syslog(LogLevel l) {
        switch (l) {
            case LogLevel::DEBUG: return LOG_DEBUG;
            case LogLevel::INFO:  return LOG_INFO;
            case LogLevel::WARN:  return LOG_WARNING;
            case LogLevel::ERROR: return LOG_ERR;
            case LogLevel::FATAL: return LOG_CRIT;
            default: return LOG_NOTICE;
        }
    }
#endif
public:
    static void set_level(LogLevel l) { level() = l; }
    static LogLevel get_level() { return level(); }
    static void init(const char* ident) {
#if __has_include(<syslog.h>)
        openlog(ident, LOG_PID | LOG_NDELAY, LOG_DAEMON);
#else
        (void)ident;
#endif
    }
    static void close() {
#if __has_include(<syslog.h>)
        closelog();
#endif
    }
    static void log(LogLevel lvl, const char* msg) {
#if __has_include(<syslog.h>)
        syslog(lvl_to_syslog(lvl), "%s", msg);
#else
        (void)lvl; std::cerr << msg << std::endl;
#endif
    }
    static void log(LogLevel lvl, const std::string& msg) { log(lvl, msg.c_str()); }
};

#define LOG(lvl, msg) do { std::ostringstream _oss; _oss << msg; \
    node669427::subsys::Logger::log(node669427::subsys::LogLevel::lvl, _oss.str()); } while(0)

// -- Enums from v1 common.hpp ------------------------------------
enum class NodeRole : uint8_t { A = 0, B = 1, C = 2, D = 3, E = 4, F = 5, G = 255 };
enum class ServiceState : uint8_t { HEALTHY = 0, DEGRADED = 1, CRITICAL = 2, UNKNOWN = 3, STOPPED = 4 };
enum class AttackType : uint8_t {
    NONE = 0, PORT_SCAN = 1, BRUTE_FORCE = 2, DDOS_SYN = 3, DDOS_UDP = 4,
    DDOS_ICMP = 5, DNS_TUNNEL = 6, C2_BEACON = 7, DATA_EXFIL = 8, L7_HTTP = 9,
    L7_HTTPS = 10, L7_APPLICATION = 11
};
enum class TrapTrigger : uint8_t {
    SOURCE_PROBE = 1, PORT_SWEEP = 2, RATE_VIOLATION = 3, PATTERN_MATCH = 4,
    CREDENTIAL_TRAP = 5, DECOY_ACCESS = 6, ANOMALY_BEHAVIOR = 7, PROTOCOL_VIOLATION = 8,
    THREAT_INTEL_HIT = 9, GEO_VIOLATION = 10
};

inline const char* role_name(NodeRole r) {
    switch(r) { case NodeRole::A: return "a"; case NodeRole::B: return "b"; case NodeRole::C: return "c";
    case NodeRole::D: return "d"; case NodeRole::E: return "e"; case NodeRole::F: return "f"; default: return "g"; }
}
inline const char* state_name(ServiceState s) {
    switch(s) { case ServiceState::HEALTHY: return "ok"; case ServiceState::DEGRADED: return "warn";
    case ServiceState::CRITICAL: return "crit"; case ServiceState::STOPPED: return "stop"; default: return "unk"; }
}
inline const char* attack_name(AttackType a) {
    switch(a) { case AttackType::NONE: return "-"; case AttackType::PORT_SCAN: return "pscan"; case AttackType::BRUTE_FORCE: return "brute";
    case AttackType::DDOS_SYN: return "syn"; case AttackType::DDOS_UDP: return "udp"; case AttackType::DDOS_ICMP: return "icmp";
    case AttackType::DNS_TUNNEL: return "dns"; case AttackType::C2_BEACON: return "c2"; case AttackType::DATA_EXFIL: return "exfil";
    case AttackType::L7_HTTP: return "h"; case AttackType::L7_HTTPS: return "hs"; default: return "app"; }
}

// -- Security event packet (binary, packed) --------------------
#pragma pack(push, 1)
struct SecurityEventPacket {
    uint8_t magic[4] = {0x43, 0x45, 0x53, 0x45};
    uint32_t timestamp;
    uint8_t node_role;
    uint8_t attack_type;
    uint8_t severity;
    uint16_t source_port;
    uint32_t source_ip;
    uint32_t signature;
    uint8_t flags;
    uint16_t payload_len = 0;
    uint8_t reserved = 0;
};
#pragma pack(pop)
static_assert(sizeof(SecurityEventPacket) == 25, "SEPacket must be 25 bytes");

// -- Constants from v1 common.hpp --------------------------------
constexpr uint32_t DDOS_SYN_THRESHOLD = 10000;
constexpr uint32_t DDOS_UDP_THRESHOLD = 50000;
constexpr uint32_t DDOS_ICMP_THRESHOLD = 20000;
constexpr uint32_t PORT_SCAN_THRESHOLD = 100;
constexpr uint32_t BRUTE_FORCE_THRESHOLD = 50;
constexpr uint32_t C2_BEACON_THRESHOLD = 20;
constexpr uint16_t DNS_TUNNEL_QUERY_THRESHOLD = 500;
constexpr uint32_t EXFIL_BYTES_THRESHOLD = 104857600;
constexpr uint32_t MAX_EVENT_AGE_SEC = 300;
constexpr uint32_t KEY_ROTATION_DAYS = 30;
constexpr uint32_t SESSION_TIMEOUT_SEC = 60;
constexpr uint16_t MAX_PACKET_SIZE = 65535;
constexpr size_t   HMAC_LEN = 32;
constexpr uint32_t MAX_SCRIPT_OUTPUT = 65536;
constexpr uint8_t  NONCE_SIZE = 24;
constexpr uint8_t  KEY_SIZE = 32;

// -- Utility functions from v1 common.hpp -----------------------
inline std::string hex_encode(const uint8_t* data, size_t len) {
    std::ostringstream oss;
    oss << std::hex << std::setfill('0');
    for (size_t i = 0; i < len; ++i) oss << std::setw(2) << static_cast<int>(data[i]);
    return oss.str();
}
inline std::vector<uint8_t> hex_decode(const std::string& hex) {
    std::vector<uint8_t> out;
    out.reserve(hex.size() / 2);
    for (size_t i = 0; i + 1 < hex.size(); i += 2) {
        int b = std::stoi(hex.substr(i, 2), nullptr, 16);
        out.push_back(static_cast<uint8_t>(b));
    }
    return out;
}
inline uint64_t now_epoch() {
    return std::chrono::duration_cast<std::chrono::seconds>(
        std::chrono::system_clock::now().time_since_epoch()).count();
}
inline std::string iso_timestamp() {
    auto t = std::time(nullptr);
    std::tm tm;
    gmtime_r(&t, &tm);
    char buf[32];
    std::strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%SZ", &tm);
    return std::string(buf);
}
inline void secure_zero(void* ptr, size_t len) {
    volatile unsigned char* p = static_cast<volatile unsigned char*>(ptr);
    while (len--) *p++ = 0;
}

template<size_t N>
class SecureBuffer {
    uint8_t data_[N];
public:
    SecureBuffer() { std::memset(data_, 0, N); }
    ~SecureBuffer() { secure_zero(data_, N); }
    SecureBuffer(const SecureBuffer&) = delete;
    SecureBuffer& operator=(const SecureBuffer&) = delete;
    SecureBuffer(SecureBuffer&& other) noexcept { std::memcpy(data_, other.data_, N); secure_zero(other.data_, N); }
    SecureBuffer& operator=(SecureBuffer&& other) noexcept {
        if (this != &other) { secure_zero(data_, N); std::memcpy(data_, other.data_, N); secure_zero(other.data_, N); }
        return *this;
    }
    uint8_t* data() { return data_; }
    const uint8_t* data() const { return data_; }
    size_t size() const { return N; }
    void clear() { secure_zero(data_, N); }
    bool is_zero() const {
        volatile uint8_t acc = 0;
        for (size_t i = 0; i < N; ++i) acc |= data_[i];
        return acc == 0;
    }
};

template<typename T>
class TSQueue {
    std::queue<T> q_;
    mutable std::mutex m_;
    std::condition_variable cv_;
public:
    void push(const T& v) { std::lock_guard<std::mutex> l(m_); q_.push(v); cv_.notify_one(); }
    void push(T&& v) { std::lock_guard<std::mutex> l(m_); q_.push(std::move(v)); cv_.notify_one(); }
    bool pop(T& v, int timeout_ms = -1) {
        std::unique_lock<std::mutex> l(m_);
        if (timeout_ms < 0) { cv_.wait(l, [this] { return !q_.empty(); }); }
        else { if (!cv_.wait_for(l, std::chrono::milliseconds(timeout_ms), [this] { return !q_.empty(); })) return false; }
        v = std::move(q_.front()); q_.pop(); return true;
    }
    bool empty() const { std::lock_guard<std::mutex> l(m_); return q_.empty(); }
    size_t size() const { std::lock_guard<std::mutex> l(m_); return q_.size(); }
    void clear() { std::lock_guard<std::mutex> l(m_); while (!q_.empty()) q_.pop(); }
};

inline void disguise_process(const char* name) {
#ifdef __linux__
    #include <sys/prctl.h>
    prctl(PR_SET_NAME, name, 0, 0, 0);
#else
    (void)name;
#endif
}

// -- Firewall rule struct (from v1 bridge.hpp) -----------------
struct FirewallRule {
    std::string chain;
    std::string action;
    std::string protocol;
    std::string src;
    std::string dst;
    uint16_t dport = 0;
    std::string comment;
    uint32_t expire_at = 0;
};

// ──────────────────────────────────────────────────────────────
// EngineConfig — v1 subsystem configuration (extends NodeConfig)
// ──────────────────────────────────────────────────────────────
struct EngineConfig {
    std::string node_id;
    NodeRole node_role = NodeRole::G;
    std::string hostname;
    std::string origin_url = "http://127.0.0.1:7171";
    std::string wg_ip;
    uint16_t listen_port = 8301;
    std::string key_file = std::string(E_KEYS) + "/master.key";
    std::string config_file = E_CFG;
    std::string scripts_dir = E_SCRIPTS;
    std::string scripts_enc = E_SCRIPTS_ENC;
    std::string watch_dir = E_WATCH;
    uint32_t heartbeat_interval_s = 10;
    uint32_t watchdog_interval_s = 5;
    uint32_t ddos_check_interval_s = 1;
    uint32_t failover_timeout_ms = 30000;
    uint32_t chattr_check_interval_s = 5;
    uint32_t ddos_syn_threshold = 10000;
    uint32_t ddos_udp_threshold = 50000;
    uint32_t ddos_http_err_threshold = 500;
    uint32_t ddos_bw_threshold_mb = 5000;
    bool enable_lockdown = true;
    bool drop_privileges = false;
    std::string run_user = "sysd-engine";
    std::string run_group = "sysd-engine";
    size_t thread_pool_size = 4;
    bool enable_heartbeat = true;
    bool enable_watchdog = true;
    bool enable_ddos = true;
    bool enable_failover = true;
    bool enable_scripts = true;
    bool enable_firewall = true;

    // TOOL_ID dispatch: loaded from engine.json tool_map
    // Each s3rv1c3agent knows its tools by TOOL_ID → disguised filename
    std::string tool_dir = "/opt/binary/tools";  // per-node tool directory
    std::unordered_map<std::string, std::string> tool_map; // TOOL_ID → filename

    // Resolve TOOL_ID to full path: tool_dir + "/" + tool_map[tool_id]
    std::string resolve_tool(const std::string& tool_id) const {
        auto it = tool_map.find(tool_id);
        if (it == tool_map.end()) return "";
        return tool_dir + "/" + it->second;
    }

    // Reverse lookup: filename → TOOL_ID (for logging)
    std::string tool_id_for(const std::string& filename) const {
        for (const auto& [id, name] : tool_map) {
            if (name == filename) return id;
        }
        return "????";
    }
};

// ──────────────────────────────────────────────────────────────
// Subsystem ThreadPool (v1 ThreadPool — separate from HttpServer's pool)
// ──────────────────────────────────────────────────────────────
class SubsysThreadPool {
public:
    explicit SubsysThreadPool(size_t num_threads);
    ~SubsysThreadPool();
    template<typename F, typename... Args>
    auto submit(F&& f, Args&&... args) -> std::future<decltype(f(args...))> {
        using ReturnType = decltype(f(args...));
        auto task = std::make_shared<std::packaged_task<ReturnType()>>(
            std::bind(std::forward<F>(f), std::forward<Args>(args)...)
        );
        std::future<ReturnType> result = task->get_future();
        {
            std::lock_guard<std::mutex> lock(mutex_);
            if (shutdown_) throw std::runtime_error("SubsysThreadPool: shutdown");
            tasks_.emplace([task]() { (*task)(); });
        }
        cv_.notify_one();
        return result;
    }
    size_t pending() const {
        std::lock_guard<std::mutex> lock(mutex_);
        return tasks_.size();
    }
private:
    std::vector<std::thread> workers_;
    std::queue<std::function<void()>> tasks_;
    mutable std::mutex mutex_;
    std::condition_variable cv_;
    bool shutdown_ = false;
};

// ──────────────────────────────────────────────────────────────
// HbMgr — Heartbeat Manager
// ──────────────────────────────────────────────────────────────
class HbMgr {
public:
    HbMgr(OriginBridge* bridge, EngineConfig* cfg);
    ~HbMgr();
    void start();
    void stop();
    bool running() const { return running_.load(); }
    void set_metrics(uint8_t cpu, uint8_t mem, uint8_t disk, uint32_t peers) {
        cpu_pct_.store(cpu);
        mem_pct_.store(mem);
        disk_pct_.store(disk);
        wg_peers_.store(peers);
    }
private:
    void run_loop();
    OriginBridge* bridge_;
    EngineConfig* cfg_;
    std::atomic<bool> running_{false};
    std::thread thread_;
    std::atomic<uint8_t> cpu_pct_{0};
    std::atomic<uint8_t> mem_pct_{0};
    std::atomic<uint8_t> disk_pct_{0};
    std::atomic<uint32_t> wg_peers_{0};
};

// ──────────────────────────────────────────────────────────────
// WdMgr — Watchdog Manager
// ──────────────────────────────────────────────────────────────
class WdMgr {
public:
    WdMgr(EngineConfig* cfg);
    ~WdMgr();
    void start();
    void stop();
    bool running() const { return running_.load(); }
private:
    void run_loop();
    EngineConfig* cfg_;
    std::atomic<bool> running_{false};
    std::thread thread_;
};

// ──────────────────────────────────────────────────────────────
// DdMon — DDoS Monitor
// ──────────────────────────────────────────────────────────────
class DdMon {
public:
    DdMon(EngineConfig* cfg);
    ~DdMon();
    void start();
    void stop();
    bool running() const { return running_.load(); }
    AttackType current_attack() const { return static_cast<AttackType>(current_attack_.load()); }
    bool under_attack() const { return current_attack() != AttackType::NONE; }
    void update_counters(uint32_t syn, uint32_t udp, uint32_t http5xx, uint32_t bw) {
        syn_pps_.store(syn);
        udp_pps_.store(udp);
        http_5xx_per_sec_.store(http5xx);
        bw_mbps_.store(bw);
    }
private:
    void run_loop();
    EngineConfig* cfg_;
    std::atomic<bool> running_{false};
    std::thread thread_;
    std::atomic<uint8_t> current_attack_{static_cast<uint8_t>(AttackType::NONE)};
    std::atomic<uint32_t> syn_pps_{0};
    std::atomic<uint32_t> udp_pps_{0};
    std::atomic<uint32_t> http_5xx_per_sec_{0};
    std::atomic<uint32_t> bw_mbps_{0};
};

// ──────────────────────────────────────────────────────────────
// FoMgr — Failover Manager
// ──────────────────────────────────────────────────────────────
class FoMgr {
public:
    FoMgr(OriginBridge* bridge, EngineConfig* cfg);
    ~FoMgr();
    void start();
    void stop();
    bool running() const { return running_.load(); }
    bool trigger_failover(const std::string& node);
    bool recover_node(const std::string& node);
    bool is_failover_active() const { return failover_active_.load(); }
private:
    void run_loop();
    OriginBridge* bridge_;
    EngineConfig* cfg_;
    std::atomic<bool> running_{false};
    std::thread thread_;
    std::atomic<bool> failover_active_{false};
    std::string failed_node_;
    std::mutex failover_mutex_;
};

// ──────────────────────────────────────────────────────────────
// ScMgr — Script Manager
// ──────────────────────────────────────────────────────────────
class ScMgr {
public:
    explicit ScMgr(EngineConfig* cfg);
    ~ScMgr();
    void start();
    void stop();
    bool running() const { return running_.load(); }
    std::pair<int, std::string> execute_script(const std::string& name, const std::vector<std::string>& args = {});
    bool reload_scripts();
private:
    void run_loop();
    void watch_directory();
    void load_whitelist();
    EngineConfig* cfg_;
    std::atomic<bool> running_{false};
    std::thread thread_;
    int watch_fd_ = -1;
    int watch_wd_ = -1;
    std::unordered_set<std::string> script_whitelist_;
    mutable std::mutex whitelist_mutex_;
};

// ──────────────────────────────────────────────────────────────
// FwMgr — Firewall Manager
// ──────────────────────────────────────────────────────────────
class FwMgr {
public:
    FwMgr(EngineConfig* cfg);
    ~FwMgr();
    void start();
    void stop();
    bool running() const { return running_.load(); }
    bool apply_rule(const FirewallRule& rule);
    bool apply_rules(const std::vector<FirewallRule>& rules);
    bool clear_dynamic_rules();
    bool block_ip(const std::string& ip, const std::string& reason, uint32_t expire_at = 0);
    bool unblock_ip(const std::string& ip);
private:
    void run_loop();
    EngineConfig* cfg_;
    std::atomic<bool> running_{false};
    std::thread thread_;
    struct BlockEntry { std::string ip; uint32_t expire_at; std::string reason; };
    std::vector<BlockEntry> active_blocks_;
    mutable std::mutex blocks_mutex_;
};

// ──────────────────────────────────────────────────────────────
// LdMgr — Lockdown Manager
// ──────────────────────────────────────────────────────────────
class LdMgr {
public:
    LdMgr(FwMgr* fw, OriginBridge* bridge, EngineConfig* cfg);
    ~LdMgr();
    bool enter_lockdown(const std::string& reason);
    bool exit_lockdown();
    bool is_locked_down() const { return locked_down_.load(); }
    std::string lockdown_reason() const {
        std::lock_guard<std::mutex> lock(mutex_);
        return lockdown_reason_;
    }
private:
    FwMgr* fw_;
    OriginBridge* bridge_;
    EngineConfig* cfg_;
    std::atomic<bool> locked_down_{false};
    std::string lockdown_reason_;
    mutable std::mutex mutex_;
    std::vector<FirewallRule> saved_rules_;
};

} // namespace subsys
} // namespace node669427
