#include "config.h"
#include <cctype>
#include <cstdlib>
#include <fstream>
#include <stdexcept>

static void trim(std::string& s) {
    while (!s.empty() && std::isspace((unsigned char)s.front())) s.erase(0, 1);
    while (!s.empty() && std::isspace((unsigned char)s.back())) s.pop_back();
}

static std::string section_name(const std::string& line) {
    auto a = line.find('['), b = line.find(']');
    if (a == std::string::npos || b == std::string::npos || b <= a) return "";
    return line.substr(a + 1, b - a - 1);
}

static bool parse_kv(const std::string& line, std::string& key, std::string& val) {
    auto eq = line.find('=');
    if (eq == std::string::npos) return false;
    key = line.substr(0, eq); trim(key);
    val = line.substr(eq + 1); trim(val);
    return !key.empty();
}

static double to_double(const std::string& s, double def) {
    try { return std::stod(s); } catch (...) { return def; }
}

static int to_int(const std::string& s, int def) {
    try { return std::stoi(s); } catch (...) { return def; }
}

AppConfig parse_ini(const std::string& path) {
    AppConfig cfg;
    std::ifstream f(path);
    if (!f) throw std::runtime_error("cannot open config: " + path);

    std::string line, section;
    int src_idx = -1;

    auto ensure_source = [&](int idx) {
        while (static_cast<int>(cfg.sources.size()) <= idx)
            cfg.sources.emplace_back();
    };

    while (std::getline(f, line)) {
        trim(line);
        if (line.empty() || line[0] == '#' || line[0] == ';') continue;

        if (line[0] == '[') {
            section = section_name(line);
            if (section.compare(0, 7, "source.") == 0) {
                src_idx = std::atoi(section.c_str() + 7);
                ensure_source(src_idx);
            } else {
                src_idx = -1;
            }
            continue;
        }

        std::string key, val;
        if (!parse_kv(line, key, val)) continue;

        if (src_idx >= 0 && src_idx < static_cast<int>(cfg.sources.size())) {
            auto& s = cfg.sources[src_idx];
            if      (key == "label")           s.label           = val;
            else if (key == "host")            s.host            = val;
            else if (key == "port")            s.port            = static_cast<uint16_t>(to_int(val, 44500));
            else if (key == "multicast_group") s.multicast_group = val;
            else if (key == "data_port")       s.data_port       = static_cast<uint16_t>(to_int(val, 0));
        } else if (section == "display") {
            if      (key == "fps")             cfg.display.fps            = to_int(val, 30);
            else if (key == "width")           cfg.display.width          = to_int(val, 1400);
            else if (key == "height")          cfg.display.height         = to_int(val, 900);
            else if (key == "opengl_version")  cfg.display.opengl_version = to_int(val, 2);
        } else if (section == "trigger") {
            if      (key == "pretrigger_sec")  cfg.trigger.pretrigger_sec  = to_double(val, 0.01);
            else if (key == "posttrigger_sec") cfg.trigger.posttrigger_sec = to_double(val, 0.09);
            // Legacy ms keys
            else if (key == "pretrigger_ms")   cfg.trigger.pretrigger_sec  = to_double(val, 10) / 1000.0;
            else if (key == "posttrigger_ms")  cfg.trigger.posttrigger_sec = to_double(val, 90) / 1000.0;
        }
    }

    return cfg;
}
