#include "dps/config.hpp"

#include <cctype>
#include <cstdlib>
#include <fstream>
#include <sstream>
#include <stdexcept>

namespace dps {

namespace {

std::string trim(const std::string &value) {
    std::size_t left = 0;
    while (left < value.size() && std::isspace(static_cast<unsigned char>(value[left]))) {
        ++left;
    }
    std::size_t right = value.size();
    while (right > left && std::isspace(static_cast<unsigned char>(value[right - 1]))) {
        --right;
    }
    return value.substr(left, right - left);
}

bool parse_bool(const std::string &value) {
    return value == "1" || value == "true" || value == "TRUE" || value == "yes" || value == "on";
}

std::string to_lower(std::string value) {
    for (char &ch : value) {
        ch = static_cast<char>(std::tolower(static_cast<unsigned char>(ch)));
    }
    return value;
}

std::string env_or(const char *name, const std::string &fallback) {
#ifdef _WIN32
    char *raw = nullptr;
    std::size_t size = 0;
    if (_dupenv_s(&raw, &size, name) != 0 || raw == nullptr) {
        return fallback;
    }
    std::string value(raw);
    std::free(raw);
    return value;
#else
    const char *raw = std::getenv(name);
    return raw == nullptr ? fallback : std::string(raw);
#endif
}

}  // namespace

AppConfig load_config(const std::string &path) {
    AppConfig config;

    std::ifstream input(path);
    if (!input.good()) {
        throw std::runtime_error("failed to open config file: " + path);
    }

    std::string line;
    while (std::getline(input, line)) {
        line = trim(line);
        if (line.empty() || line[0] == '#') {
            continue;
        }
        const std::size_t pos = line.find('=');
        if (pos == std::string::npos) {
            continue;
        }
        const std::string key = trim(line.substr(0, pos));
        const std::string value = trim(line.substr(pos + 1));

        if (key == "server.host") config.server.host = value;
        else if (key == "server.port") config.server.port = std::stoi(value);
        else if (key == "server.trust_proxy") config.server.trust_proxy = parse_bool(value);
        else if (key == "server.proxy_header") config.server.proxy_header = value;
        else if (key == "jwt.secret") config.jwt.secret = value;
        else if (key == "jwt.expiration_seconds") config.jwt.expiration_seconds = std::stoll(value);
        else if (key == "logging.level") config.logging.level = value;
        else if (key == "logging.http_summary") config.logging.http_summary = parse_bool(value);
        else if (key == "logging.http_dump") config.logging.http_dump = parse_bool(value);
        else if (key == "logging.http_max_body") config.logging.http_max_body = std::stoi(value);
        else if (key == "features.video_enabled") config.features.video_enabled = parse_bool(value);
        else if (key == "features.payment_enabled") config.features.payment_enabled = parse_bool(value);
        else if (key == "database.host") config.database.host = value;
        else if (key == "database.port") config.database.port = std::stoi(value);
        else if (key == "database.name") config.database.name = value;
        else if (key == "database.user") config.database.user = value;
        else if (key == "database.password") config.database.password = value;
        else if (key == "database.ssl_mode") config.database.ssl_mode = to_lower(value);
        else if (key == "database.ssl_ca") config.database.ssl_ca = value;
        else if (key == "database.plugin_dir") config.database.plugin_dir = value;
        else if (key == "paths.configfile") config.paths.configfile = value;
        else if (key == "paths.file_root") config.paths.file_root = value;
        else if (key == "paths.file_map") config.paths.file_map = value;
        else if (key == "paths.script_root") config.paths.script_root = value;
        else if (key == "paths.dps_root") config.paths.dps_root = value;
        else if (key == "paths.client_user_script_root") config.paths.client_user_script_root = value;
    }

    config.server.host = env_or("DPS_SERVER_HOST", config.server.host);
    config.server.proxy_header = env_or("DPS_SERVER_PROXY_HEADER", config.server.proxy_header);
    config.jwt.secret = env_or("DPS_JWT_SECRET", config.jwt.secret);
    config.database.host = env_or("DPS_DB_HOST", config.database.host);
    config.database.user = env_or("DPS_DB_USER", config.database.user);
    config.database.password = env_or("DPS_DB_PASSWORD", config.database.password);
    config.database.name = env_or("DPS_DB_NAME", config.database.name);
    config.database.ssl_mode = to_lower(env_or("DPS_DB_SSL_MODE", config.database.ssl_mode));
    config.database.ssl_ca = env_or("DPS_DB_SSL_CA", config.database.ssl_ca);
    config.database.plugin_dir = env_or("DPS_DB_PLUGIN_DIR", config.database.plugin_dir);

    return config;
}

}  // namespace dps
