#include "StageEditorPanel.h"
#include "../utils/FileDialog.h"
#include "../core/commands/LayerCommands.h"
#include <imgui.h>
#include <memory>
#include <string>

namespace UsdLayerManager {

StageEditorPanel::StageEditorPanel() {}

StageEditorPanel::~StageEditorPanel() {}

// ---------------------------------------------------------------------------
void StageEditorPanel::Render() {
    if (!m_layerManager) return;

    auto iconBtn = [&](const char* id, Icon icon, const char* fallback) -> bool {
        if (m_iconManager) {
            ImTextureID tex = m_iconManager->Get(icon);
            return ImGui::ImageButton(id, ImTextureRef(tex), ImVec2(18.f, 18.f));
        }
        return ImGui::Button(fallback);
    };

    // Toolbar
    ImGui::Text("Stage Editor");
    ImGui::SameLine(ImGui::GetWindowWidth() - 100);

    if (iconBtn("##refresh", Icon::Refresh, "R"))
        m_layerManager->Refresh();
    if (ImGui::IsItemHovered()) ImGui::SetTooltip("Refresh");

    ImGui::SameLine();
    if (iconBtn("##addExisting", Icon::FolderOpen, "+E")) {
        std::string path = FileDialog::OpenFile(
            "USD Files (*.usd;*.usda;*.usdc)\0*.usd;*.usda;*.usdc\0All Files (*.*)\0*.*\0",
            "Add Sublayer");
        if (!path.empty()) {
            if (m_commandHistory)
                m_commandHistory->Push(
                    std::make_unique<LayerCreateCommand>(m_layerManager, path));
            else
                m_layerManager->CreateSublayer(path);
        }
    }
    if (ImGui::IsItemHovered()) ImGui::SetTooltip("Add Existing Sublayer");

    ImGui::SameLine();
    if (iconBtn("##createNew", Icon::FilePlus, "+N")) {
        std::string path = FileDialog::SaveFile(
            "USD Files (*.usd;*.usda;*.usdc)\0*.usd;*.usda;*.usdc\0All Files (*.*)\0*.*\0",
            "Create New Sublayer",
            "usd");
        if (!path.empty() && m_layerManager)
            m_layerManager->CreateNewSublayer(path);
    }
    if (ImGui::IsItemHovered()) ImGui::SetTooltip("Create New Sublayer");

    ImGui::Separator();

    auto allLayers = m_layerManager->GetLayerStack();
    if (allLayers.empty()) {
        ImGui::TextDisabled("No stage loaded");
        return;
    }

    std::vector<LayerInfo> fixed, sublayers;
    for (const auto& li : allLayers) {
        if (li.isRootLayer || li.isSessionLayer)
            fixed.push_back(li);
        else
            sublayers.push_back(li);
    }

    RenderFixedLayers(fixed);

    ImGui::Spacing();
    ImGui::TextDisabled("Sublayers");
    ImGui::Separator();

    RenderSublayerList(sublayers);

}

// ---------------------------------------------------------------------------
void StageEditorPanel::RenderFixedLayers(const std::vector<LayerInfo>& layers) {
    if (layers.empty()) return;

    if (!ImGui::BeginTable("FixedLayerTable", 4,
            ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersInnerV |
            ImGuiTableFlags_SizingFixedFit))
        return;

    ImGui::TableSetupColumn("##dirty", ImGuiTableColumnFlags_WidthFixed, 14.0f);
    ImGui::TableSetupColumn("Name",    ImGuiTableColumnFlags_WidthStretch);
    ImGui::TableSetupColumn("Type",    ImGuiTableColumnFlags_WidthFixed, 70.0f);
    ImGui::TableSetupColumn("##et",    ImGuiTableColumnFlags_WidthFixed, 28.0f);

    for (const auto& li : layers) {
        ImGui::TableNextRow();
        ImGui::PushID(li.identifier.c_str());

        ImGui::TableSetColumnIndex(0);
        if (li.isDirty)
            ImGui::TextColored(ImVec4(1.0f, 0.6f, 0.2f, 1.0f), "*");
        else
            ImGui::TextDisabled(" ");

        ImGui::TableSetColumnIndex(1);
        ImVec4 color = li.isRootLayer
            ? ImVec4(0.5f, 1.0f, 0.5f, 1.0f)
            : ImVec4(0.5f, 0.7f, 1.0f, 1.0f);
        ImGui::TextColored(color, "%s", li.displayName.c_str());
        if (ImGui::IsItemHovered() && !li.realPath.empty())
            ImGui::SetTooltip("%s\n%s", li.identifier.c_str(), li.realPath.c_str());

        ImGui::TableSetColumnIndex(2);
        if (li.isRootLayer)
            ImGui::TextColored(ImVec4(0.5f, 1.0f, 0.5f, 1.0f), "Root");
        else
            ImGui::TextColored(ImVec4(0.5f, 0.7f, 1.0f, 1.0f), "Session");

        ImGui::TableSetColumnIndex(3);
        {
            bool renderLayerActive = m_renderLayerManager && !m_renderLayerManager->IsDefaultActive();
            bool isET = li.isEditTarget;
            ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2.0f, 1.0f));
            ImGui::BeginDisabled(renderLayerActive);
            if (ImGui::Checkbox("##et", &isET) && isET)
                m_layerManager->SetEditTarget(li.identifier);
            ImGui::EndDisabled();
            ImGui::PopStyleVar();
            if (ImGui::IsItemHovered())
                ImGui::SetTooltip(renderLayerActive ? "Edit target is locked to the active render layer"
                                  : li.isEditTarget  ? "Edit target (active)"
                                                      : "Set as edit target");
        }

        ImGui::PopID();
    }

    ImGui::EndTable();
}

// ---------------------------------------------------------------------------
void StageEditorPanel::RenderSublayerList(const std::vector<LayerInfo>& sublayers) {
    if (sublayers.empty()) {
        ImGui::TextDisabled("  No sublayers");
        return;
    }

    float tableHeight = ImGui::GetContentRegionAvail().y;

    if (!ImGui::BeginTable("SublayerTable", 5,
            ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersInnerV |
            ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_ScrollY,
            ImVec2(0, tableHeight)))
        return;

    ImGui::TableSetupScrollFreeze(0, 1);
    ImGui::TableSetupColumn("##drag",  ImGuiTableColumnFlags_WidthFixed, 14.0f);
    ImGui::TableSetupColumn("##dirty", ImGuiTableColumnFlags_WidthFixed, 14.0f);
    ImGui::TableSetupColumn("Name",    ImGuiTableColumnFlags_WidthStretch);
    ImGui::TableSetupColumn("##et",    ImGuiTableColumnFlags_WidthFixed, 28.0f);
    ImGui::TableSetupColumn("Muted",   ImGuiTableColumnFlags_WidthFixed, 55.0f);

    // Custom header row: pen icon for the ET column, text for the rest.
    ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
    ImGui::TableSetColumnIndex(2); ImGui::TableHeader("Name");
    ImGui::TableSetColumnIndex(3);
    {
        float cellW = ImGui::GetContentRegionAvail().x;
        float iconW = 14.0f;
        float off   = (cellW - iconW) * 0.5f;
        if (off > 0.0f) ImGui::SetCursorPosX(ImGui::GetCursorPosX() + off);
        if (m_iconManager)
            ImGui::Image(ImTextureRef(m_iconManager->Get(Icon::Pen)), ImVec2(iconW, iconW));
        else
            ImGui::TextUnformatted("ET");
        if (ImGui::IsItemHovered()) ImGui::SetTooltip("Edit Target");
    }
    ImGui::TableSetColumnIndex(4); ImGui::TableHeader("Muted");

    for (int i = 0; i < static_cast<int>(sublayers.size()); i++) {
        const auto& li = sublayers[i];
        ImGui::TableNextRow();
        ImGui::PushID(i);

        // Col 0: invisible span-all Selectable for row selection / drag / context menu.
        ImGui::TableSetColumnIndex(0);
        ImVec2 rowStart = ImGui::GetCursorScreenPos(); // save before Selectable moves cursor

        bool isSelected = (m_selectedIdx == i);
        if (ImGui::Selectable("##row", isSelected,
                ImGuiSelectableFlags_SpanAllColumns |
                ImGuiSelectableFlags_AllowOverlap,
                ImVec2(0, 0)))
            m_selectedIdx = i;

        // Context menu: must come immediately after the span-all Selectable so
        // BeginPopupContextItem sees it as the "last item" and responds to
        // right-click anywhere in the row.
        RenderSublayerContextMenu(i, sublayers);

        // Drag source: also attached to the Selectable (left-button drag).
        if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_SourceAllowNullID)) {
            ImGui::SetDragDropPayload("SUBLAYER_IDX", &i, sizeof(int));
            ImGui::Text("%s", li.displayName.c_str());
            ImGui::EndDragDropSource();
        }

        // Drop target on the Selectable.
        if (ImGui::BeginDragDropTarget()) {
            if (const ImGuiPayload* payload =
                    ImGui::AcceptDragDropPayload("SUBLAYER_IDX")) {
                int src = *static_cast<const int*>(payload->Data);
                int dst = i;
                if (src != dst) {
                    std::vector<std::string> before, after;
                    for (const auto& sl : sublayers) before.push_back(sl.identifier);
                    after = before;
                    std::string moved = after[src];
                    after.erase(after.begin() + src);
                    after.insert(after.begin() + dst, moved);
                    if (m_commandHistory) {
                        m_commandHistory->Push(std::make_unique<LayerReorderCommand>(
                            m_layerManager, before, after));
                    } else {
                        LayerReorderCommand cmd(m_layerManager, before, after);
                        static_cast<ICommand&>(cmd).Execute();
                    }
                }
            }
            ImGui::EndDragDropTarget();
        }

        // "=" drag handle: overlay at col 0 using the saved screen position so it
        // sits inside the row, not below it (TableSetColumnIndex only resets X).
        ImGui::SetCursorScreenPos(rowStart);
        ImGui::TextDisabled("=");

        // Col 1: dirty indicator
        ImGui::TableSetColumnIndex(1);
        if (li.isDirty)
            ImGui::TextColored(ImVec4(1.0f, 0.6f, 0.2f, 1.0f), "*");
        else
            ImGui::TextDisabled(" ");

        bool isRenderLayer = RenderLayerManager::IsRenderLayerSublayer(li.layer);
        bool renderLayerActive = m_renderLayerManager && !m_renderLayerManager->IsDefaultActive();

        // Col 2: layer name
        ImGui::TableSetColumnIndex(2);
        ImVec4 nameColor = li.isMuted
            ? ImVec4(0.5f, 0.5f, 0.5f, 1.0f)
            : ImVec4(1.0f, 1.0f, 1.0f, 1.0f);
        ImGui::TextColored(nameColor, "%s", li.displayName.c_str());
        if (ImGui::IsItemHovered() && !li.realPath.empty())
            ImGui::SetTooltip("%s\n%s", li.identifier.c_str(), li.realPath.c_str());
        if (isRenderLayer) {
            ImGui::SameLine();
            ImGui::TextColored(ImVec4(0.9f, 0.7f, 0.2f, 1.0f), "[RL]");
            if (ImGui::IsItemHovered())
                ImGui::SetTooltip("Managed from the Render Layer panel");
        }

        // Col 3: edit target checkbox — checking sets this layer as edit target;
        // unchecking does nothing (there is always an active edit target).
        ImGui::TableSetColumnIndex(3);
        {
            bool isET = li.isEditTarget;
            ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2.0f, 1.0f));
            ImGui::BeginDisabled(renderLayerActive);
            if (ImGui::Checkbox("##et", &isET) && isET)
                m_layerManager->SetEditTarget(li.identifier);
            ImGui::EndDisabled();
            ImGui::PopStyleVar();
            if (ImGui::IsItemHovered())
                ImGui::SetTooltip(renderLayerActive ? "Edit target is locked to the active render layer"
                                  : li.isEditTarget  ? "Edit target (active)"
                                                      : "Set as edit target");
        }

        // Col 4: mute checkbox — disabled for render-layer sublayers, which
        // RenderLayerManager mutes/unmutes exclusively as layers are switched.
        ImGui::TableSetColumnIndex(4);
        {
            bool muted = li.isMuted;
            ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2.0f, 1.0f));
            ImGui::BeginDisabled(isRenderLayer);
            if (ImGui::Checkbox("##muted", &muted)) {
                if (muted) m_layerManager->MuteLayer(li.identifier);
                else       m_layerManager->UnmuteLayer(li.identifier);
            }
            ImGui::EndDisabled();
            ImGui::PopStyleVar();
            if (isRenderLayer && ImGui::IsItemHovered())
                ImGui::SetTooltip("Managed from the Render Layer panel");
        }

        ImGui::PopID();
    }

    ImGui::EndTable();
}

// ---------------------------------------------------------------------------
void StageEditorPanel::RenderSublayerContextMenu(int i,
        const std::vector<LayerInfo>& sublayers) {
    if (!ImGui::BeginPopupContextItem(("ctx_" + std::to_string(i)).c_str()))
        return;

    const auto& li = sublayers[i];
    bool isRenderLayer = RenderLayerManager::IsRenderLayerSublayer(li.layer);
    bool renderLayerActive = m_renderLayerManager && !m_renderLayerManager->IsDefaultActive();

    if (ImGui::MenuItem(li.isMuted ? "Unmute" : "Mute", nullptr, false, !isRenderLayer)) {
        if (li.isMuted) m_layerManager->UnmuteLayer(li.identifier);
        else            m_layerManager->MuteLayer(li.identifier);
    }
    if (isRenderLayer && ImGui::IsItemHovered())
        ImGui::SetTooltip("Managed from the Render Layer panel");

    if (!li.isEditTarget &&
        ImGui::MenuItem("Set as Edit Target", nullptr, false, !renderLayerActive))
        m_layerManager->SetEditTarget(li.identifier);
    if (renderLayerActive && !li.isEditTarget && ImGui::IsItemHovered())
        ImGui::SetTooltip("Edit target is locked to the active render layer");

    ImGui::Separator();

    bool canUp   = (i > 0);
    bool canDown = (i < static_cast<int>(sublayers.size()) - 1);

    auto buildBeforeAfter = [&](int a, int b,
            std::vector<std::string>& before,
            std::vector<std::string>& after) {
        for (const auto& sl : sublayers) before.push_back(sl.identifier);
        after = before;
        std::swap(after[a], after[b]);
    };

    if (ImGui::MenuItem("Move Up", nullptr, false, canUp)) {
        std::vector<std::string> before, after;
        buildBeforeAfter(i, i - 1, before, after);
        if (m_commandHistory)
            m_commandHistory->Push(
                std::make_unique<LayerReorderCommand>(m_layerManager, before, after));
        else {
            LayerReorderCommand cmd(m_layerManager, before, after);
            static_cast<ICommand&>(cmd).Execute();
        }
    }

    if (ImGui::MenuItem("Move Down", nullptr, false, canDown)) {
        std::vector<std::string> before, after;
        buildBeforeAfter(i, i + 1, before, after);
        if (m_commandHistory)
            m_commandHistory->Push(
                std::make_unique<LayerReorderCommand>(m_layerManager, before, after));
        else {
            LayerReorderCommand cmd(m_layerManager, before, after);
            static_cast<ICommand&>(cmd).Execute();
        }
    }

    ImGui::Separator();

    if (ImGui::MenuItem("Remove", nullptr, false, !isRenderLayer)) {
        if (m_commandHistory)
            m_commandHistory->Push(
                std::make_unique<LayerRemoveCommand>(m_layerManager, i));
        else
            m_layerManager->RemoveSublayer(i);
    }
    if (isRenderLayer && ImGui::IsItemHovered())
        ImGui::SetTooltip("Managed from the Render Layer panel");

    ImGui::EndPopup();
}


} // namespace UsdLayerManager
