#include "gfx/dag_panel.h"
#include "gfx/dag_catalog.h"
#include "imgui.h"
#include <algorithm>
#include <string>

namespace fn::gfx {

static constexpr int MAX_NODES = 16;

static uint64_t s_next_id = 1;

static std::string make_id() {
    return "n" + std::to_string(s_next_id++);
}

static ImVec4 kind_color(DagKind kind) {
    switch (kind) {
        case DagKind::Gen:    return ImVec4(0.25f, 0.55f, 0.90f, 1.0f);
        case DagKind::Op:     return ImVec4(0.65f, 0.40f, 0.90f, 1.0f);
        case DagKind::Blend:  return ImVec4(0.90f, 0.65f, 0.15f, 1.0f);
        case DagKind::Output: return ImVec4(0.85f, 0.25f, 0.25f, 1.0f);
    }
    return ImVec4(1, 1, 1, 1);
}

static const char* kind_label(DagKind kind) {
    switch (kind) {
        case DagKind::Gen:    return "Gen";
        case DagKind::Op:     return "Op";
        case DagKind::Blend:  return "Blend";
        case DagKind::Output: return "Output";
    }
    return "?";
}

bool dag_panel(std::vector<DagStep>& pipeline) {
    bool changed = false;

    // Toolbar
    int sz = static_cast<int>(pipeline.size());
    if (ImGui::Button("+ Add Node")) {
        ImGui::OpenPopup("dag_add_popup");
    }
    ImGui::SameLine();
    ImGui::Text("%d/%d nodes", sz, MAX_NODES);
    ImGui::SameLine();
    if (ImGui::Button("Clear") && !pipeline.empty()) {
        ImGui::OpenPopup("dag_clear_confirm");
    }

    if (ImGui::BeginPopupModal("dag_clear_confirm", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
        ImGui::Text("Vaciar el pipeline?");
        if (ImGui::Button("Si")) {
            pipeline.clear();
            changed = true;
            ImGui::CloseCurrentPopup();
        }
        ImGui::SameLine();
        if (ImGui::Button("No")) {
            ImGui::CloseCurrentPopup();
        }
        ImGui::EndPopup();
    }

    if (ImGui::BeginPopup("dag_add_popup")) {
        const char* kind_names[] = { "Gen", "Op", "Blend" };
        DagKind kinds[] = { DagKind::Gen, DagKind::Op, DagKind::Blend };
        for (int k = 0; k < 3; ++k) {
            if (ImGui::BeginMenu(kind_names[k])) {
                for (const auto& def : dag_catalog()) {
                    if (def.kind != kinds[k]) continue;
                    if (ImGui::MenuItem(def.label.c_str())) {
                        if (static_cast<int>(pipeline.size()) < MAX_NODES) {
                            DagStep step;
                            step.id   = make_id();
                            step.name = def.name;
                            step.params = def.param_defaults;
                            if (def.kind == DagKind::Blend && !pipeline.empty()) {
                                int src = std::max(0, static_cast<int>(pipeline.size()) - 2);
                                step.source_ids[1] = pipeline[static_cast<size_t>(src)].id;
                            }
                            pipeline.push_back(step);
                            changed = true;
                        }
                    }
                }
                ImGui::EndMenu();
            }
        }
        ImGui::EndPopup();
    }

    ImGui::Separator();

    // Pipeline list
    int delete_idx = -1;
    int move_up_idx = -1;
    int move_down_idx = -1;
    int drop_src_idx = -1;
    int drop_target_idx = -1;

    ImGui::BeginChild("dag_pipeline_scroll", ImVec2(0, 0), false);

    for (int i = 0; i < static_cast<int>(pipeline.size()); ++i) {
        DagStep& step = pipeline[static_cast<size_t>(i)];
        const DagNodeDef* def = dag_find(step.name);
        if (!def) continue;

        ImVec4 col = kind_color(def->kind);
        ImGui::PushID(i);

        ImGui::PushStyleColor(ImGuiCol_Header,        ImVec4(col.x*0.4f, col.y*0.4f, col.z*0.4f, 0.8f));
        ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(col.x*0.5f, col.y*0.5f, col.z*0.5f, 0.9f));
        ImGui::PushStyleColor(ImGuiCol_HeaderActive,  ImVec4(col.x*0.6f, col.y*0.6f, col.z*0.6f, 1.0f));

        std::string header = std::string("#") + std::to_string(i) + " " + def->label + " [" + kind_label(def->kind) + "]";
        bool open = ImGui::CollapsingHeader(header.c_str());

        ImGui::PopStyleColor(3);

        if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_SourceAllowNullID)) {
            ImGui::SetDragDropPayload("DAG_STEP", &i, sizeof(int));
            ImGui::Text("Move %s", def->label.c_str());
            ImGui::EndDragDropSource();
        }
        if (ImGui::BeginDragDropTarget()) {
            if (const ImGuiPayload* pl = ImGui::AcceptDragDropPayload("DAG_STEP")) {
                drop_src_idx = *static_cast<const int*>(pl->Data);
                drop_target_idx = i;
            }
            ImGui::EndDragDropTarget();
        }

        if (open) {
            ImGui::Indent(8.0f);

            // Source selector for blends
            if (def->kind == DagKind::Blend) {
                std::vector<std::string> prev_labels;
                std::vector<int> prev_indices;
                for (int j = 0; j < i; ++j) {
                    const DagNodeDef* pdef = dag_find(pipeline[static_cast<size_t>(j)].name);
                    std::string lbl = "out_" + std::to_string(j);
                    if (pdef) lbl += " (" + pdef->label + ")";
                    prev_labels.push_back(lbl);
                    prev_indices.push_back(j);
                }

                int current_src = std::max(0, i - 2);
                if (!step.source_ids[1].empty()) {
                    for (int j = 0; j < i; ++j) {
                        if (pipeline[static_cast<size_t>(j)].id == step.source_ids[1]) {
                            current_src = j;
                            break;
                        }
                    }
                }

                if (!prev_labels.empty()) {
                    std::vector<const char*> items;
                    for (const auto& l : prev_labels) items.push_back(l.c_str());
                    int sel = current_src;
                    if (ImGui::Combo("Source", &sel, items.data(), static_cast<int>(items.size()))) {
                        if (sel >= 0 && sel < i) {
                            step.source_ids[1] = pipeline[static_cast<size_t>(sel)].id;
                            changed = true;
                        }
                    }
                } else {
                    ImGui::TextDisabled("(requiere al menos un nodo antes)");
                }
            }

            // Controls
            int pcount = static_cast<int>(step.params.size());
            for (const auto& ctrl : def->controls) {
                std::string uid_label = ctrl.label + "##" + step.id + std::to_string(&ctrl - def->controls.data());
                if (ctrl.kind == DagControl::Kind::Slider) {
                    int pidx = ctrl.param_idx[0];
                    if (pidx >= 0 && pidx < pcount) {
                        ImGui::SliderFloat(uid_label.c_str(), &step.params[static_cast<size_t>(pidx)], ctrl.min, ctrl.max);
                    }
                } else if (ctrl.kind == DagControl::Kind::XY) {
                    int px = ctrl.param_idx[0];
                    int py = ctrl.param_idx[1];
                    if (px >= 0 && px < pcount && py >= 0 && py < pcount && py == px + 1) {
                        ImGui::SliderFloat2(uid_label.c_str(), &step.params[static_cast<size_t>(px)], ctrl.min, ctrl.max);
                    }
                } else if (ctrl.kind == DagControl::Kind::Color) {
                    int pr = ctrl.param_idx[0];
                    if (pr >= 0 && pr + 2 < pcount) {
                        ImGui::ColorEdit3(uid_label.c_str(), &step.params[static_cast<size_t>(pr)]);
                    }
                }
            }

            // Action buttons
            ImGui::Spacing();
            ImGui::BeginDisabled(i == 0);
            if (ImGui::SmallButton("Move Up")) {
                move_up_idx = i;
            }
            ImGui::EndDisabled();
            ImGui::SameLine();
            ImGui::BeginDisabled(i == static_cast<int>(pipeline.size()) - 1);
            if (ImGui::SmallButton("Move Down")) {
                move_down_idx = i;
            }
            ImGui::EndDisabled();
            ImGui::SameLine();
            ImGui::PushStyleColor(ImGuiCol_Button,        ImVec4(0.7f, 0.15f, 0.15f, 0.8f));
            ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.9f, 0.2f,  0.2f,  1.0f));
            ImGui::PushStyleColor(ImGuiCol_ButtonActive,  ImVec4(1.0f, 0.3f,  0.3f,  1.0f));
            if (ImGui::SmallButton("Delete")) {
                delete_idx = i;
            }
            ImGui::PopStyleColor(3);

            ImGui::Unindent(8.0f);
        }

        ImGui::PopID();
        ImGui::Spacing();
    }

    ImGui::EndChild();

    // Apply deferred mutations
    if (delete_idx >= 0) {
        pipeline.erase(pipeline.begin() + delete_idx);
        changed = true;
    }
    if (move_up_idx > 0) {
        std::swap(pipeline[static_cast<size_t>(move_up_idx)], pipeline[static_cast<size_t>(move_up_idx - 1)]);
        changed = true;
    }
    if (move_down_idx >= 0 && move_down_idx < static_cast<int>(pipeline.size()) - 1) {
        std::swap(pipeline[static_cast<size_t>(move_down_idx)], pipeline[static_cast<size_t>(move_down_idx + 1)]);
        changed = true;
    }
    if (drop_src_idx >= 0 && drop_target_idx >= 0 && drop_src_idx != drop_target_idx &&
        drop_src_idx < static_cast<int>(pipeline.size()) &&
        drop_target_idx < static_cast<int>(pipeline.size())) {
        DagStep moved = pipeline[static_cast<size_t>(drop_src_idx)];
        pipeline.erase(pipeline.begin() + drop_src_idx);
        int target = drop_target_idx;
        if (drop_src_idx < drop_target_idx) target--;
        pipeline.insert(pipeline.begin() + target, moved);
        changed = true;
    }

    return changed;
}

} // namespace fn::gfx
