#include "engine_config.h"

#include <fstream>
#include <sstream>
#include <iostream>
#include <cstdlib>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/stat.h>

namespace node669427 {

static std::string trim(const std::string& str) {
    auto start = str.find_first_not_of(" \t\r\n");
    if (start == std::string::npos) return "";
    auto end = str.find_last_not_of(" \t\r\n");
    return str.substr(start, end - start + 1);
}

static std::string resolve_env(const std::string& val) {
    if (val.length() > 3 && val.substr(0, 2) == "${" && val.back() == '}') {
        std::string env_var = val.substr(2, val.length() - 3);
        if (const char* env_val = std::getenv(env_var.c_str())) {
            return std::string(env_val);
        }
        return "";
    }
    return val;
}

static bool is_valid_ip(const std::string& ip) {
    struct sockaddr_in sa;
    return inet_pton(AF_INET, ip.c_str(), &(sa.sin_addr)) != 0;
}

NodeConfig NodeConfig::load(const std::string& config_path) {
    NodeConfig cfg;
    std::ifstream f(config_path);
    if (!f.is_open()) {
        std::cerr << "[Config] Cannot open " << config_path << std::endl;
        exit(1);
    }
    std::string line;
    while (std::getline(f, line)) {
        line = trim(line);
        if (line.empty() || line[0] == ';' || line[0] == '#') continue;
        auto eq = line.find('=');
        if (eq == std::string::npos) continue;
        
        std::string key = trim(line.substr(0, eq));
        std::string val = resolve_env(trim(line.substr(eq + 1)));

        if (key == "node_id") cfg.node_id = val;
        else if (key == "role") cfg.role = val;
        else if (key == "bind_address") cfg.bind_address = val;
        else if (key == "bind_port") cfg.listen_port = std::stoi(val);
        else if (key == "hmac_key_path") cfg.hmac_key_path = val;
        else if (key == "vault_path") cfg.vault_path = val;
        else if (key == "max_body_size") cfg.max_body_size = std::stoi(val);
        else if (key == "max_concurrent") cfg.max_concurrent = std::stoi(val);
        else if (key == "rate_limit") cfg.rate_limit = std::stoi(val);
        else if (key == "rate_burst") cfg.rate_burst = std::stoi(val);
        else if (key == "recv_timeout") cfg.recv_timeout = std::stoi(val);
        else if (key == "send_timeout") cfg.send_timeout = std::stoi(val);
        else if (key == "session_ttl") cfg.session_ttl = std::stoi(val);
        else if (key == "max_payment_amount") cfg.max_payment_amount = std::stod(val);
        else if (key == "stripe_endpoint") cfg.services.stripe_bridge_url = val;
        else if (key == "db_host") cfg.db_host = val;
        else if (key == "db_port") cfg.db_port = std::stoi(val);
        else if (key == "db_user") cfg.db_user = val;
        else if (key == "db_pass") cfg.db_pass = val;
        else if (key == "tron_signer_url") cfg.services.tron_signer_url = val;
        else if (key == "xmr_rpc_url") cfg.services.xmr_wallet_url = val;
        else if (key == "log_level") cfg.log_level = val;
        else if (key == "log_path") cfg.log_path = val;
        else if (key == "log_max_size") cfg.log_max_size = std::stoi(val);
        else if (key == "log_max_files") cfg.log_max_files = std::stoi(val);
    }
    return cfg;
}

void NodeConfig::validate() const {
    if (node_id.empty()) { std::cerr << "Missing node_id\n"; exit(1); }
    if (bind_address != "127.0.0.1" && bind_address != "172.28.50.1") { std::cerr << "bind_address must be 127.0.0.1 or 172.28.50.1\n"; exit(1); }
    if (listen_port < 1 || listen_port > 65535) { std::cerr << "Invalid port\n"; exit(1); }
    if (hmac_key_path.empty()) { std::cerr << "Missing hmac_key_path\n"; exit(1); }
    if (vault_path.empty()) { std::cerr << "Missing vault_path\n"; exit(1); }
    if (db_host.empty() || !is_valid_ip(db_host)) { std::cerr << "Invalid db_host\n"; exit(1); }
    if (db_user.empty()) { std::cerr << "Missing db_user\n"; exit(1); }
    if (db_pass.empty()) { std::cerr << "Missing db_pass\n"; exit(1); }
    if (max_payment_amount <= 0) { std::cerr << "Invalid max_payment_amount\n"; exit(1); }
}

NodeConfig NodeConfig::from_args(int argc, char* argv[]) {
    NodeConfig cfg;
    std::string config_path = "/opt/apache/engine/config/engine.conf";

    for (int i = 1; i < argc; ++i) {
        std::string arg = argv[i];
        if (arg == "--config" && i + 1 < argc) {
            config_path = argv[++i];
        } else if (arg == "--node-id" && i + 1 < argc) {
            cfg.node_id = argv[i + 1];
            i++;
        } else if (arg == "--role" && i + 1 < argc) {
            cfg.role = argv[i + 1];
            i++;
        }
    }

    if (access(config_path.c_str(), R_OK) == 0) {
        NodeConfig file_cfg = load(config_path);
        file_cfg.node_id = cfg.node_id.empty() ? file_cfg.node_id : cfg.node_id;
        file_cfg.role = cfg.role.empty() ? file_cfg.role : cfg.role;
        file_cfg.validate();
        return file_cfg;
    } else {
        std::cerr << "Cannot read config file: " << config_path << "\n";
        exit(1);
    }
}

} // namespace node669427
