#include "views.h"
#include "jobs.h"

#include "core/icons_tabler.h"
#include "core/tokens.h"

#include "imgui.h"

#include <cfloat>
#include <chrono>
#include <cstdio>

namespace ge {

namespace {

// Cache de la lista de jobs. Se refresca cada N frames para no abrir SQLite
// en cada frame. ~10 Hz es suficiente para una progress bar fluida.
struct JobsCache {
    std::vector<JobRow> rows;
    int     last_frame_refresh = -100;
    int     filter_idx         = 0;       // 0=all 1=active 2=done 3=error
    char    buf[8] = {};
};
JobsCache g_jobs_cache;

const char* status_icon(const std::string& s) {
    if (s == "queued")    return TI_HOURGLASS;
    if (s == "running")   return TI_PLAYER_PLAY;
    if (s == "done")      return TI_CHECK;
    if (s == "error")     return TI_ALERT_CIRCLE;
    if (s == "cancelled") return TI_X;
    return TI_QUESTION_MARK;
}

ImVec4 status_color(const std::string& s) {
    if (s == "running")   return ImVec4(0.36f, 0.78f, 1.0f, 1.0f);
    if (s == "done")      return ImVec4(0.40f, 0.85f, 0.55f, 1.0f);
    if (s == "error")     return ImVec4(0.95f, 0.45f, 0.45f, 1.0f);
    if (s == "cancelled") return ImVec4(0.65f, 0.65f, 0.65f, 1.0f);
    if (s == "queued")    return ImVec4(0.85f, 0.78f, 0.45f, 1.0f);
    return ImVec4(0.7f, 0.7f, 0.7f, 1.0f);
}

std::string format_duration(long long started, long long finished) {
    if (started <= 0) return "—";
    long long end = finished > 0 ? finished
                    : std::chrono::duration_cast<std::chrono::milliseconds>(
                          std::chrono::system_clock::now().time_since_epoch())
                          .count();
    long long ms = end - started;
    if (ms < 0) ms = 0;
    char b[32];
    if (ms < 1000)            std::snprintf(b, sizeof(b), "%lld ms", ms);
    else if (ms < 60'000)     std::snprintf(b, sizeof(b), "%.1f s",  ms / 1000.0);
    else                      std::snprintf(b, sizeof(b), "%.1f m",  ms / 60'000.0);
    return b;
}

bool filter_match(const std::string& status, int idx) {
    switch (idx) {
        case 0: return true;                                          // all
        case 1: return status == "queued" || status == "running";     // active
        case 2: return status == "done";
        case 3: return status == "error" || status == "cancelled";
        default: return true;
    }
}

} // namespace

void views_jobs(AppState& app) {
    if (!app.panel_jobs) return;

    if (!ImGui::Begin("Jobs", &app.panel_jobs)) {
        ImGui::End();
        return;
    }

    // Refresh cache cada ~10 frames (~6 Hz a 60fps).
    int frame = ImGui::GetFrameCount();
    if (frame - g_jobs_cache.last_frame_refresh > 10) {
        jobs_list(&g_jobs_cache.rows, 200);
        g_jobs_cache.last_frame_refresh = frame;
    }

    // Header: counters + filtro.
    JobCounters c = jobs_counters();
    ImGui::TextColored(status_color("running"), "%s", TI_PLAYER_PLAY);
    ImGui::SameLine(); ImGui::Text("%d", c.running);
    ImGui::SameLine(0, 16);
    ImGui::TextColored(status_color("queued"), "%s", TI_HOURGLASS);
    ImGui::SameLine(); ImGui::Text("%d", c.queued);
    ImGui::SameLine(0, 16);
    ImGui::TextColored(status_color("done"), "%s", TI_CHECK);
    ImGui::SameLine(); ImGui::Text("%d", c.done);
    ImGui::SameLine(0, 16);
    ImGui::TextColored(status_color("error"), "%s", TI_ALERT_CIRCLE);
    ImGui::SameLine(); ImGui::Text("%d", c.error + c.cancelled);

    ImGui::SameLine(0, 24);
    const char* filter_labels[] = { "All", "Active", "Done", "Errors" };
    ImGui::SetNextItemWidth(100);
    ImGui::Combo("##jobs_filter", &g_jobs_cache.filter_idx,
                 filter_labels, IM_ARRAYSIZE(filter_labels));

    ImGui::Separator();

    // Tabla.
    ImGuiTableFlags tflags = ImGuiTableFlags_Borders |
                             ImGuiTableFlags_RowBg |
                             ImGuiTableFlags_SizingStretchProp |
                             ImGuiTableFlags_ScrollY;
    if (ImGui::BeginTable("jobs_table", 6, tflags,
                          ImVec2(0, ImGui::GetContentRegionAvail().y - 4))) {
        ImGui::TableSetupScrollFreeze(0, 1);
        ImGui::TableSetupColumn("Status",   ImGuiTableColumnFlags_WidthFixed, 90);
        ImGui::TableSetupColumn("Enricher", ImGuiTableColumnFlags_WidthStretch, 1.5f);
        ImGui::TableSetupColumn("Target",   ImGuiTableColumnFlags_WidthStretch, 2.0f);
        ImGui::TableSetupColumn("Progress", ImGuiTableColumnFlags_WidthStretch, 2.0f);
        ImGui::TableSetupColumn("Time",     ImGuiTableColumnFlags_WidthFixed, 70);
        ImGui::TableSetupColumn("##actions",ImGuiTableColumnFlags_WidthFixed, 80);
        ImGui::TableHeadersRow();

        for (const auto& r : g_jobs_cache.rows) {
            if (!filter_match(r.status, g_jobs_cache.filter_idx)) continue;
            ImGui::PushID(r.id.c_str());
            ImGui::TableNextRow();

            // Status.
            ImGui::TableSetColumnIndex(0);
            ImGui::TextColored(status_color(r.status), "%s %s",
                               status_icon(r.status), r.status.c_str());

            // Enricher.
            ImGui::TableSetColumnIndex(1);
            ImGui::TextUnformatted(r.enricher_id.c_str());

            // Target.
            ImGui::TableSetColumnIndex(2);
            if (!r.node_name.empty()) {
                ImGui::TextUnformatted(r.node_name.c_str());
            } else if (!r.node_id.empty()) {
                ImGui::TextDisabled("%s", r.node_id.c_str());
            } else {
                ImGui::TextDisabled("(global)");
            }

            // Progress.
            ImGui::TableSetColumnIndex(3);
            if (r.status == "running" || r.status == "queued") {
                ImGui::ProgressBar((float)r.progress, ImVec2(-FLT_MIN, 0),
                                   r.stage.empty() ? nullptr : r.stage.c_str());
            } else if (r.status == "error" && !r.error.empty()) {
                ImGui::TextColored(status_color("error"), "%s",
                                   r.error.size() > 64
                                       ? (r.error.substr(0, 64) + "…").c_str()
                                       : r.error.c_str());
                if (ImGui::IsItemHovered()) {
                    ImGui::SetTooltip("%s", r.error.c_str());
                }
            } else if (r.status == "done" && !r.result_json.empty()) {
                ImGui::TextDisabled("%s",
                    r.result_json.size() > 80
                        ? (r.result_json.substr(0, 80) + "…").c_str()
                        : r.result_json.c_str());
                if (ImGui::IsItemHovered() && r.result_json.size() > 80) {
                    ImGui::SetTooltip("%s", r.result_json.c_str());
                }
            } else {
                ImGui::TextDisabled("—");
            }

            // Time.
            ImGui::TableSetColumnIndex(4);
            ImGui::TextDisabled("%s",
                format_duration(r.started_at, r.finished_at).c_str());

            // Actions.
            ImGui::TableSetColumnIndex(5);
            if (r.status == "queued" || r.status == "running") {
                if (ImGui::SmallButton("Cancel")) {
                    jobs_cancel(r.id.c_str());
                }
            } else {
                if (ImGui::SmallButton("Delete")) {
                    jobs_delete(r.id.c_str());
                }
            }

            ImGui::PopID();
        }
        ImGui::EndTable();
    }

    ImGui::End();
}

} // namespace ge
