#include "app_settings.h"

#include "imgui.h"
#include "../../framework/app_base.h"

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <vector>

namespace fn_ui {

namespace {

AppSettings g_settings;
bool        g_font_dirty   = false;
bool        g_window_open  = false;

// app_settings.ini vive en <exe_dir>/local_files/ (convencion del
// registry — todos los archivos escribibles bajo local_files/).
const char* settings_path() { return fn::local_path("app_settings.ini"); }

const float k_sizes[] = {12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 18.0f, 20.0f};
constexpr int k_size_count = sizeof(k_sizes) / sizeof(k_sizes[0]);
constexpr int k_font_count = 5;

struct ExtraSection {
    std::string id;
    std::string title;
    std::function<void()> render;
};
std::vector<ExtraSection> g_extra_sections;

const char* skip_ws(const char* s) {
    while (*s == ' ' || *s == '\t') ++s;
    return s;
}

void parse_line(const char* line) {
    if (line[0] == '#' || line[0] == ';' || line[0] == '\n' || line[0] == '\0') return;
    const char* eq = std::strchr(line, '=');
    if (!eq) return;

    std::string key(line, eq - line);
    while (!key.empty() && (key.back() == ' ' || key.back() == '\t')) key.pop_back();

    const char* val = skip_ws(eq + 1);
    if (key == "show_fps") {
        g_settings.show_fps = (val[0] == '1' || val[0] == 't' || val[0] == 'T');
    } else if (key == "font_id") {
        int v = std::atoi(val);
        if (v >= 0 && v < k_font_count) g_settings.font_id = static_cast<FontId>(v);
    } else if (key == "font_size_px") {
        float v = static_cast<float>(std::atof(val));
        if (v >= 8.0f && v <= 64.0f) g_settings.font_size_px = v;
    }
}

} // namespace

AppSettings& settings() { return g_settings; }

void settings_load() {
    FILE* f = std::fopen(settings_path(), "r");
    if (!f) return;
    char line[256];
    while (std::fgets(line, sizeof(line), f)) parse_line(line);
    std::fclose(f);
}

void settings_save() {
    FILE* f = std::fopen(settings_path(), "w");
    if (!f) {
        std::fprintf(stderr, "[fn_ui] settings_save: no pude abrir %s\n", settings_path());
        return;
    }
    std::fprintf(f, "# fn_registry app_settings.ini — autogenerado, editable\n");
    std::fprintf(f, "show_fps     = %d\n", g_settings.show_fps ? 1 : 0);
    std::fprintf(f, "font_id      = %d  # 0=Karla 1=Roboto 2=DroidSans(default) 3=Cousine 4=ProggyClean\n",
                 static_cast<int>(g_settings.font_id));
    std::fprintf(f, "font_size_px = %.1f\n", g_settings.font_size_px);
    std::fclose(f);
}

void settings_mark_font_dirty()    { g_font_dirty = true; }
bool settings_consume_font_dirty() { bool d = g_font_dirty; g_font_dirty = false; return d; }

const char* font_filename(FontId id) {
    switch (id) {
        case FontId::Karla:       return "Karla-Regular.ttf";
        case FontId::Roboto:      return "Roboto-Medium.ttf";
        case FontId::DroidSans:   return "DroidSans.ttf";
        case FontId::Cousine:     return "Cousine-Regular.ttf";
        case FontId::ProggyClean: return ""; // bitmap default ImGui
    }
    return "";
}

const char* font_label(FontId id) {
    switch (id) {
        case FontId::Karla:       return "Karla";
        case FontId::Roboto:      return "Roboto Medium";
        case FontId::DroidSans:   return "Droid Sans";
        case FontId::Cousine:     return "Cousine (mono)";
        case FontId::ProggyClean: return "ProggyClean (bitmap)";
    }
    return "?";
}

bool settings_window_is_open()        { return g_window_open; }
void settings_window_set_open(bool v) { g_window_open = v; }
void settings_window_toggle()         { g_window_open = !g_window_open; }

bool settings_window_menu_item(const char* label) {
    if (ImGui::MenuItem(label)) {
        settings_window_set_open(true);
        return true;
    }
    return false;
}

void settings_window_add_section(const char* id, const char* title,
                                 std::function<void()> render) {
    for (auto& s : g_extra_sections) {
        if (s.id == id) {
            s.title  = title;
            s.render = std::move(render);
            return;
        }
    }
    g_extra_sections.push_back({id, title, std::move(render)});
}

void settings_window_render() {
    if (!g_window_open) return;

    ImGui::SetNextWindowSize(ImVec2(420, 360), ImGuiCond_FirstUseEver);
    if (!ImGui::Begin("Settings", &g_window_open)) {
        ImGui::End();
        return;
    }

    bool changed = false;

    // --- Core: Display ---
    if (ImGui::CollapsingHeader("Display", ImGuiTreeNodeFlags_DefaultOpen)) {
        if (ImGui::Checkbox("Show FPS overlay", &g_settings.show_fps)) {
            changed = true;
        }
    }

    // --- Core: Typography ---
    if (ImGui::CollapsingHeader("Typography", ImGuiTreeNodeFlags_DefaultOpen)) {
        // Font combo
        const char* current_font = font_label(g_settings.font_id);
        if (ImGui::BeginCombo("Font", current_font)) {
            for (int i = 0; i < k_font_count; ++i) {
                FontId id = static_cast<FontId>(i);
                bool sel = (g_settings.font_id == id);
                if (ImGui::Selectable(font_label(id), sel)) {
                    if (!sel) {
                        g_settings.font_id = id;
                        settings_mark_font_dirty();
                        changed = true;
                    }
                }
                if (sel) ImGui::SetItemDefaultFocus();
            }
            ImGui::EndCombo();
        }

        // Size combo (preset values) — cambios aplican inmediatamente via
        // style.FontSizeBase. NO marcan font dirty (no rebuild de atlas).
        char size_label[16];
        std::snprintf(size_label, sizeof(size_label), "%.0f px", g_settings.font_size_px);
        if (ImGui::BeginCombo("Size", size_label)) {
            for (int i = 0; i < k_size_count; ++i) {
                float sz = k_sizes[i];
                char label[16];
                std::snprintf(label, sizeof(label), "%.0f px", sz);
                bool sel = (g_settings.font_size_px == sz);
                if (ImGui::Selectable(label, sel)) {
                    if (!sel) {
                        g_settings.font_size_px = sz;
                        changed = true;
                    }
                }
                if (sel) ImGui::SetItemDefaultFocus();
            }
            ImGui::EndCombo();
        }

        // Slider libre — drag continuo, escala instantanea
        float sz = g_settings.font_size_px;
        if (ImGui::SliderFloat("Size (free)", &sz, 10.0f, 32.0f, "%.0f px")) {
            if (sz != g_settings.font_size_px) {
                g_settings.font_size_px = sz;
                changed = true;
            }
        }

        ImGui::TextDisabled("Tamaño aplica al instante. Cambio de fuente = 1 frame.");
    }

    // --- Extra sections registradas por la app ---
    for (const auto& s : g_extra_sections) {
        if (s.render && ImGui::CollapsingHeader(s.title.c_str(), ImGuiTreeNodeFlags_DefaultOpen)) {
            ImGui::PushID(s.id.c_str());
            s.render();
            ImGui::PopID();
        }
    }

    // --- Footer ---
    ImGui::Separator();
    ImGui::TextDisabled("app_settings.ini junto al ejecutable. Auto-save al cambiar.");

    ImGui::End();

    if (changed) settings_save();
}

} // namespace fn_ui
