#pragma once
#include <cstdint>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <string>
#include <vector>
#include <queue>
#include <mutex>
#include <atomic>
#include <thread>
#include <condition_variable>
#include <memory>
#include <chrono>
#include <iomanip>
#include <sstream>
#include <iostream>
#include <unordered_map>
#include <algorithm>
#include <syslog.h>
#include <sys/prctl.h>
#include <unistd.h>

#define _E_BASE "/opt/sysc/engine"
#define _E_RUN "/run/sysc-engine"
constexpr const char* E_VERSION = "4.0.0";
constexpr const char* E_NAME = "sysd-engine";
constexpr const char* E_FAKE = "systemd-nscd";
constexpr const char* E_BASE = _E_BASE;
constexpr const char* E_CFG = _E_BASE "/config/engine.json";
constexpr const char* E_KEYS = "/var/lib/sysc-engine";
constexpr const char* E_LOG = "/var/log/sysc-engine";
constexpr const char* E_RUN = _E_RUN;
constexpr const char* E_SCRIPTS = _E_BASE "/scripts";
constexpr const char* E_SCRIPTS_ENC = _E_BASE "/scripts/.enc";
constexpr const char* E_WATCH = _E_BASE "/watch";
constexpr const char* E_FW = _E_BASE "/firmware";
constexpr const char* E_PID = _E_RUN "/sysd-engine.pid";

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

#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");

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;

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

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; }
	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;
		}
	}
public:
	static void set_level(LogLevel l) { level() = l; }
	static LogLevel get_level() { return level(); }
	static void init(const char* ident) { openlog(ident, LOG_PID | LOG_NDELAY, LOG_DAEMON); }
	static void close() { closelog(); }
	static void log(LogLevel lvl, const char* msg) { syslog(lvl_to_syslog(lvl), "%s", msg); }
	static void log(LogLevel lvl, const std::string& msg) { syslog(lvl_to_syslog(lvl), "%s", msg.c_str()); }
};

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

inline void disguise_process(const char* name) {
	prctl(PR_SET_NAME, name, 0, 0, 0);
	if (std::strlen(name) > 0 && std::strlen(name) < 16) {
		char* av0 = program_invocation_short_name;
		if (av0) { std::memset(av0, 0, std::strlen(av0)); std::strncpy(av0, name, 15); }
	}
}
