// data_table_drill — drill-down stack + breadcrumb de stages.
// Sub-funcion extraida de modules/data_table/data_table.cpp (issue 0107c).
//
// Rangos de lineas del fuente original:
//   - make_drill_filter      : lineas 699-706
//   - apply_drill_step       : lineas 708-718
//   - undo_drill_step        : lineas 720-730
//   - drill_up               : lineas 732-737
//   - draw_stage_breadcrumb  : lineas 1386-1483
//   - drill_into             : lineas 2898-2919

#include "viz/data_table_drill.h"
#include "core/data_table_types.h"
#include "imgui.h"

#include <cstdio>
#include <string>
#include <vector>

namespace data_table {

// ---------------------------------------------------------------------------
// make_drill_filter: crea un Filter Op::Eq para col_idx con el valor dado.
// ---------------------------------------------------------------------------
Filter make_drill_filter(int col_idx, const std::string& value) {
    Filter f;
    f.col   = col_idx;
    f.op    = Op::Eq;
    f.value = value;
    return f;
}

// ---------------------------------------------------------------------------
// apply_drill_step: inserta step.added en el stage en step.target_stage y
// actualiza st.active_stage. Retorna true si el step se aplico correctamente.
// ---------------------------------------------------------------------------
bool apply_drill_step(State& st, const DrillStep& step) {
    if (step.target_stage < 0 || step.target_stage >= (int)st.stages.size()) return false;
    Stage& s = st.stages[step.target_stage];
    int pos = step.filter_pos;
    if (pos < 0 || pos > (int)s.filters.size()) return false;
    s.filters.insert(s.filters.begin() + pos, step.added);
    st.active_stage = step.target_stage;
    return true;
}

// ---------------------------------------------------------------------------
// undo_drill_step: elimina el filter insertado por apply_drill_step y restaura
// st.active_stage a step.prev_active_stage. Retorna true si se deshizo.
// ---------------------------------------------------------------------------
bool undo_drill_step(State& st, const DrillStep& step) {
    if (step.target_stage < 0 || step.target_stage >= (int)st.stages.size()) return false;
    Stage& s = st.stages[step.target_stage];
    int pos = step.filter_pos;
    if (pos < 0 || pos >= (int)s.filters.size()) return false;
    s.filters.erase(s.filters.begin() + pos);
    if (step.prev_active_stage >= 0 && step.prev_active_stage < (int)st.stages.size())
        st.active_stage = step.prev_active_stage;
    return true;
}

// ---------------------------------------------------------------------------
// drill_up: retrocede st.active_stage en 1 si hay stages previos.
// Retorna true si se pudo retroceder.
// ---------------------------------------------------------------------------
bool drill_up(State& st) {
    if (st.stages.empty()) return false;
    if (st.active_stage <= 0) return false;
    st.active_stage -= 1;
    return true;
}

// ---------------------------------------------------------------------------
// draw_stage_breadcrumb: barra de navegacion de drill con botones < > ^ y
// selector de stages. Mutates st.drill_back/forward y st.active_stage.
// ---------------------------------------------------------------------------
void draw_stage_breadcrumb(State& st) {
    st.ensure_stage0();

    // Drill history back/forward (fase 10). Botones al inicio.
    {
        bool can_back = !st.drill_back.empty();
        ImGui::BeginDisabled(!can_back);
        if (ImGui::SmallButton("<##drill_back")) {
            DrillStep s = st.drill_back.back();
            st.drill_back.pop_back();
            if (undo_drill_step(st, s)) {
                st.drill_forward.push_back(s);
            }
        }
        ImGui::EndDisabled();
        if (can_back && ImGui::IsItemHovered())
            ImGui::SetTooltip("Drill back (%zu)", st.drill_back.size());
        ImGui::SameLine();
        bool can_fwd = !st.drill_forward.empty();
        ImGui::BeginDisabled(!can_fwd);
        if (ImGui::SmallButton(">##drill_fwd")) {
            DrillStep s = st.drill_forward.back();
            st.drill_forward.pop_back();
            if (apply_drill_step(st, s)) {
                st.drill_back.push_back(s);
            }
        }
        ImGui::EndDisabled();
        if (can_fwd && ImGui::IsItemHovered())
            ImGui::SetTooltip("Drill forward (%zu)", st.drill_forward.size());
        ImGui::SameLine();
        bool can_up = (st.active_stage > 0);
        ImGui::BeginDisabled(!can_up);
        if (ImGui::SmallButton("^##drill_up")) drill_up(st);
        ImGui::EndDisabled();
        if (can_up && ImGui::IsItemHovered())
            ImGui::SetTooltip("Drill up (stage previo, sin perder filters)");
        ImGui::SameLine();
        ImGui::TextDisabled("|");
        ImGui::SameLine();
    }

    for (int si = 0; si < (int)st.stages.size(); ++si) {
        if (si > 0) { ImGui::SameLine(); ImGui::TextDisabled(">"); ImGui::SameLine(); }

        bool active = (si == st.active_stage);
        if (active) {
            ImGui::PushStyleColor(ImGuiCol_Button,        IM_COL32( 80, 140, 200, 240));
            ImGui::PushStyleColor(ImGuiCol_ButtonHovered, IM_COL32(100, 160, 220, 240));
            ImGui::PushStyleColor(ImGuiCol_ButtonActive,  IM_COL32( 60, 120, 180, 240));
        } else {
            ImGui::PushStyleColor(ImGuiCol_Button,        IM_COL32( 70,  70,  90, 200));
            ImGui::PushStyleColor(ImGuiCol_ButtonHovered, IM_COL32( 90,  90, 120, 220));
            ImGui::PushStyleColor(ImGuiCol_ButtonActive,  IM_COL32( 55,  55,  75, 220));
        }

        char label[256];
        if (si == 0) {
            std::snprintf(label, sizeof(label), "Raw##stage%d", si);
        } else {
            const Stage& s = st.stages[si];
            std::string desc;
            for (size_t i = 0; i < s.breakouts.size() && i < 2; ++i) {
                if (i > 0) desc += ", ";
                desc += s.breakouts[i];
            }
            if (s.breakouts.size() > 2) desc += "...";
            if (desc.empty())
                std::snprintf(label, sizeof(label), "Stage %d##s%d", si, si);
            else
                std::snprintf(label, sizeof(label), "Stage %d: by %s##s%d",
                              si, desc.c_str(), si);
        }
        if (ImGui::Button(label)) st.active_stage = si;
        ImGui::PopStyleColor(3);

        if (si > 0) {
            ImGui::SameLine();
            char xlbl[32];
            std::snprintf(xlbl, sizeof(xlbl), "x##rm_s%d", si);
            if (ImGui::SmallButton(xlbl)) {
                // borra ese stage y sucesores
                while ((int)st.stages.size() > si) st.stages.pop_back();
                if (st.active_stage >= (int)st.stages.size())
                    st.active_stage = (int)st.stages.size() - 1;
                if (st.active_stage < 0) st.active_stage = 0;
                break;
            }
        }
    }
    ImGui::SameLine();
    ImGui::TextDisabled(">");
    ImGui::SameLine();
    if (ImGui::SmallButton("+ Stage##add_stage")) {
        st.stages.push_back(Stage{});
        st.active_stage = (int)st.stages.size() - 1;
    }
}

// ---------------------------------------------------------------------------
// drill_into: API publica. Anade un filter Op::Eq sobre col_name=value al
// stage (from_stage - 1) y cambia st.active_stage a ese stage previo.
// Graba el step en st.drill_back y limpia st.drill_forward (rama nueva).
// ---------------------------------------------------------------------------
void drill_into(State& st, int from_stage,
                const std::string& col_name, const std::string& value,
                const std::vector<std::string>& prev_input_headers)
{
    if (from_stage <= 0 || from_stage >= (int)st.stages.size()) return;
    int target = from_stage - 1;
    int ci = -1;
    for (size_t i = 0; i < prev_input_headers.size(); ++i) {
        if (prev_input_headers[i] == col_name) { ci = (int)i; break; }
    }
    if (ci < 0) return;

    // Fase 10: graba step en drill_back, limpia forward (rama nueva).
    DrillStep step;
    step.target_stage      = target;
    step.filter_pos        = (int)st.stages[target].filters.size();
    step.prev_active_stage = st.active_stage;
    step.added             = make_drill_filter(ci, value);
    apply_drill_step(st, step);
    st.drill_back.push_back(step);
    st.drill_forward.clear();
}

} // namespace data_table
