#include <fstream>
#include <inipp.h>
#include "data_internal.hxx"

static constexpr std::string ini_name = "config.ini";

std::shared_ptr<spdlog::logger> data_logger;

Data::Data() {
    if (!data_logger)
        data_logger = spdlog::default_logger()->clone("data");

    if (!std::filesystem::exists(files_dir))
        std::filesystem::create_directory(files_dir);

    load_config();
    load();
    validate();
    start_save_thread();
}

Data::~Data() {
    shutdown();
}

void Data::shutdown() {
    data_logger->info("Stopping data saver");
    shutdown_flag.test_and_set();
    save();
    save_thread.join();
    data_logger->info("Data saver stopped");
}

void Data::load_config() {
    inipp::Ini<char> ini;
    if (!std::filesystem::exists(ini_name)) {
        ini.sections["web"] = {
            {"port", "80"}
        };
        ini.sections["smtp"] = {
            {"host", "127.0.0.1"},
            {"port", "25"},
            {"user", "username"},
            {"pass", "password"},
            {"from", "fileserver@example.com"}
        };
        ini.sections["admin"] = {
            {"mail", "admin@example.com"}
        };
        std::ofstream f{ini_name};
        ini.generate(f);
        data_logger->critical("Missing config, generated example");
        crash();
    }
    data_logger->info("Loading config");
    std::ifstream f{ini_name};
    ini.parse(f);
    if (!ini.errors.empty()) {
        data_logger->critical("Failed to parse config:");
        for (const auto &err : ini.errors)
            data_logger->critical(err);
        crash();
    }
    if (!ini.sections.contains("web")) { data_logger->critical("Missing section web"); crash(); }
    if (!ini.sections.contains("smtp")) { data_logger->critical("Missing section smtp"); crash(); }
    if (!ini.sections.contains("admin")) { data_logger->critical("Missing section admin"); crash(); }

    std::string entry;
#define get_entry(section, key) if (!ini.sections[#section].contains(#key)) {data_logger->critical("Missing " #section ":" #key); crash();} entry = ini.sections[#section][#key]
    get_entry(web, port); config.server_port = std::stoul(entry);
    get_entry(smtp, host); config.smtp_host = entry;
    get_entry(smtp, port); config.smtp_port = std::stoul(entry);
    get_entry(smtp, user); config.smtp_user = entry;
    get_entry(smtp, pass); config.smtp_pass = entry;
    get_entry(smtp, from); config.smtp_from = entry;
    get_entry(admin, mail); config.admin_mail = entry;
#undef get_entry
}
