#include "CellGridEditor.hpp"
#include "../components/CellGrid.hpp"
#include "../components/ProceduralMaterial.hpp"
#include "../components/ProceduralTexture.hpp"
#include "../systems/FurnitureLibrary.hpp"
#include <OgreStringConverter.h>


bool CellGridEditor::renderComponent(flecs::entity entity, CellGridComponent& grid)
{
    m_currentEntity = entity;
    bool modified = false;
    
    if (ImGui::CollapsingHeader("Cell Grid", ImGuiTreeNodeFlags_DefaultOpen)) {
        ImGui::Indent();
        
        // Grid dimensions
        int dims[3] = { grid.width, grid.height, grid.depth };
        if (ImGui::InputInt3("Grid Size (W/H/D)", dims)) {
            grid.width = std::max(1, dims[0]);
            grid.height = std::max(1, dims[1]);
            grid.depth = std::max(1, dims[2]);
            modified = true;
        }
        
        // Cell size
        if (ImGui::DragFloat("Cell Size", &grid.cellSize, 0.1f, 0.5f, 20.0f)) {
            modified = true;
        }
        if (ImGui::DragFloat("Cell Height", &grid.cellHeight, 0.1f, 0.5f, 20.0f)) {
            modified = true;
        }
        if (ImGui::SliderFloat("Friction", &grid.friction, 0.0f, 1.0f, "%.2f")) {
            modified = true;
        }
        
        ImGui::Separator();
        
        // Statistics
        ImGui::Text("Cells: %zu", grid.cells.size());
        ImGui::Text("Furniture: %zu", grid.furnitureCells.size());
        
        // Cell editor
        if (ImGui::CollapsingHeader("Cells")) {
            renderCellEditor(grid);
        }
        
        // Furniture editor
        if (ImGui::CollapsingHeader("Furniture")) {
            renderFurnitureEditor(grid);
        }
        
        // Texture rectangle editor
        if (ImGui::CollapsingHeader("Texture Rectangles")) {
            renderTextureRectEditor(entity, grid);
        }
        
        // Script editor
        if (ImGui::CollapsingHeader("Generation Script")) {
            renderScriptEditor(grid);
        }
        
        ImGui::Separator();
        
        // Actions
        if (ImGui::Button("Clear All Cells")) {
            grid.clear();
            modified = true;
        }
        ImGui::SameLine();
        if (ImGui::Button("Rebuild Geometry")) {
            grid.markDirty();
            modified = true;
        }
        
        if (modified) {
            grid.markDirty();
        }
        
        ImGui::Unindent();
    }
    
    return modified;
}

void CellGridEditor::renderCellEditor(CellGridComponent& grid)
{
    // New cell input
    ImGui::InputInt3("New Cell Pos", &newCellX);
    
    if (ImGui::Button("Add/Edit Cell")) {
        auto& cell = grid.getOrCreateCell(newCellX, newCellY, newCellZ);
        selectedCellX = newCellX;
        selectedCellY = newCellY;
        selectedCellZ = newCellZ;
    }
    
    ImGui::Separator();
    
    // Selected cell editor
    Cell* cell = grid.findCell(selectedCellX, selectedCellY, selectedCellZ);
    if (cell) {
        ImGui::Text("Editing Cell: %d, %d, %d", selectedCellX, selectedCellY, selectedCellZ);
        
        auto flags = CellGridComponent::getAllFlags();
        for (const auto& [flag, name] : flags) {
            ImGui::PushID((int)flag);
            bool hasFlag = cell->hasFlag(flag);
            if (ImGui::Checkbox(name, &hasFlag)) {
                if (hasFlag) {
                    cell->setFlag(flag);
                } else {
                    cell->clearFlag(flag);
                }
                grid.markDirty();
            }
            ImGui::PopID();
        }
        
        if (ImGui::Button("Delete Cell")) {
            grid.removeCell(selectedCellX, selectedCellY, selectedCellZ);
            grid.markDirty();
        }
    } else {
        ImGui::Text("No cell selected");
    }
    
    ImGui::Separator();
    
    // List existing cells
    if (ImGui::BeginListBox("Cells", ImVec2(-FLT_MIN, 150))) {
        for (const auto& cell : grid.cells) {
            std::string label = std::to_string(cell.x) + ", " + 
                               std::to_string(cell.y) + ", " + 
                               std::to_string(cell.z) + " (flags: " +
                               std::to_string(cell.flags) + ")";
            bool isSelected = (cell.x == selectedCellX && 
                              cell.y == selectedCellY && 
                              cell.z == selectedCellZ);
            if (ImGui::Selectable(label.c_str(), isSelected)) {
                selectedCellX = cell.x;
                selectedCellY = cell.y;
                selectedCellZ = cell.z;
            }
        }
        ImGui::EndListBox();
    }
}

void CellGridEditor::renderFurnitureEditor(CellGridComponent& grid)
{
    static int fx = 0, fy = 0, fz = 0;
    static char tagsBuffer[256] = {0};
    static int selectedFurnitureIndex = -1;
    static int rotation = 0;
    
    FurnitureLibrary::getInstance().loadAll();
    const auto& defs = FurnitureLibrary::getInstance().getDefinitions();
    
    ImGui::InputInt3("Furniture Pos", &fx);
    ImGui::InputText("Tags (comma separated)", tagsBuffer, sizeof(tagsBuffer));
    
    // Furniture type dropdown
    std::string preview = selectedFurnitureIndex >= 0 && selectedFurnitureIndex < (int)defs.size()
        ? defs[selectedFurnitureIndex].name + " (" + defs[selectedFurnitureIndex].meshName + ")"
        : "Select furniture type...";
    
    if (ImGui::BeginCombo("Furniture Type", preview.c_str())) {
        for (int i = 0; i < (int)defs.size(); ++i) {
            std::string label = defs[i].name + " (" + defs[i].meshName + ")";
            bool isSelected = (selectedFurnitureIndex == i);
            if (ImGui::Selectable(label.c_str(), isSelected)) {
                selectedFurnitureIndex = i;
            }
            if (isSelected)
                ImGui::SetItemDefaultFocus();
        }
        ImGui::EndCombo();
    }
    
    ImGui::SliderInt("Rotation", &rotation, 0, 3);
    
    if (ImGui::Button("Add/Update Furniture") && selectedFurnitureIndex >= 0) {
        auto& fcell = grid.getOrCreateFurnitureCell(fx, fy, fz);
        fcell.furnitureType = defs[selectedFurnitureIndex].name;
        fcell.rotation = rotation;
        fcell.tags.clear();
        // Parse tags
        std::string tagsStr(tagsBuffer);
        size_t start = 0;
        size_t end = tagsStr.find(',');
        while (end != std::string::npos) {
            std::string tag = tagsStr.substr(start, end - start);
            tag.erase(0, tag.find_first_not_of(" \t"));
            tag.erase(tag.find_last_not_of(" \t") + 1);
            if (!tag.empty()) {
                fcell.tags.push_back(tag);
            }
            start = end + 1;
            end = tagsStr.find(',', start);
        }
        std::string lastTag = tagsStr.substr(start);
        lastTag.erase(0, lastTag.find_first_not_of(" \t"));
        lastTag.erase(lastTag.find_last_not_of(" \t") + 1);
        if (!lastTag.empty()) {
            fcell.tags.push_back(lastTag);
        }
        grid.markDirty();
    }
    
    ImGui::SameLine();
    if (ImGui::Button("Delete Furniture")) {
        grid.removeFurnitureCell(fx, fy, fz);
        grid.markDirty();
    }
    
    ImGui::Separator();
    
    // List furniture cells
    if (ImGui::BeginListBox("Furniture Cells", ImVec2(-FLT_MIN, 100))) {
        for (const auto& fcell : grid.furnitureCells) {
            std::string label = std::to_string(fcell.x) + ", " + 
                               std::to_string(fcell.y) + ", " + 
                               std::to_string(fcell.z) + ": " + fcell.furnitureType;
            if (ImGui::Selectable(label.c_str())) {
                fx = fcell.x;
                fy = fcell.y;
                fz = fcell.z;
                rotation = fcell.rotation;
                // Find index in defs
                selectedFurnitureIndex = -1;
                for (int i = 0; i < (int)defs.size(); ++i) {
                    if (defs[i].name == fcell.furnitureType) {
                        selectedFurnitureIndex = i;
                        break;
                    }
                }
                std::string tags;
                for (size_t i = 0; i < fcell.tags.size(); ++i) {
                    if (i > 0) tags += ", ";
                    tags += fcell.tags[i];
                }
                strncpy(tagsBuffer, tags.c_str(), sizeof(tagsBuffer) - 1);
            }
        }
        ImGui::EndListBox();
    }
}

void CellGridEditor::renderScriptEditor(CellGridComponent& grid)
{
    // Copy script to buffer if needed
    if (scriptBuffer[0] == '\0' && !grid.generationScript.empty()) {
        strncpy(scriptBuffer, grid.generationScript.c_str(), sizeof(scriptBuffer) - 1);
    }
    
    ImGui::InputTextMultiline("Script", scriptBuffer, sizeof(scriptBuffer),
                              ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 20),
                              ImGuiInputTextFlags_AllowTabInput);
    
    if (ImGui::IsItemDeactivatedAfterEdit()) {
        grid.generationScript = scriptBuffer;
        grid.markDirty();
    }
    
    if (ImGui::Button("Execute Script")) {
        grid.generationScript = scriptBuffer;
        // TODO: Execute Lua script
        grid.markDirty();
    }
}


void CellGridEditor::renderTextureRectEditor(flecs::entity entity, CellGridComponent& grid)
{
    // Find available texture rectangles from parent material
    flecs::entity textureEntity = flecs::entity::null();
    flecs::entity parent = entity.parent();
    while (parent.is_alive()) {
        if (parent.has<LotComponent>()) {
            auto& lot = parent.get<LotComponent>();
            if (lot.proceduralMaterialEntity.is_alive() && 
                lot.proceduralMaterialEntity.has<ProceduralMaterialComponent>()) {
                const auto& mat = lot.proceduralMaterialEntity.get<ProceduralMaterialComponent>();
                if (mat.diffuseTextureEntity.is_alive()) {
                    textureEntity = mat.diffuseTextureEntity;
                    break;
                }
            }
        }
        if (parent.has<DistrictComponent>()) {
            auto& district = parent.get<DistrictComponent>();
            if (district.proceduralMaterialEntity.is_alive() && 
                district.proceduralMaterialEntity.has<ProceduralMaterialComponent>()) {
                const auto& mat = district.proceduralMaterialEntity.get<ProceduralMaterialComponent>();
                if (mat.diffuseTextureEntity.is_alive()) {
                    textureEntity = mat.diffuseTextureEntity;
                    break;
                }
            }
        }
        if (parent.has<TownComponent>()) {
            auto& town = parent.get<TownComponent>();
            if (town.proceduralMaterialEntity.is_alive() && 
                town.proceduralMaterialEntity.has<ProceduralMaterialComponent>()) {
                const auto& mat = town.proceduralMaterialEntity.get<ProceduralMaterialComponent>();
                if (mat.diffuseTextureEntity.is_alive()) {
                    textureEntity = mat.diffuseTextureEntity;
                    break;
                }
            }
            break;
        }
        parent = parent.parent();
    }
    
    if (!textureEntity.is_alive() || !textureEntity.has<ProceduralTextureComponent>()) {
        ImGui::TextDisabled("No ProceduralMaterial with texture found in parent hierarchy");
        return;
    }
    
    const auto& texture = textureEntity.get<ProceduralTextureComponent>();
    const auto& namedRects = texture.getAllNamedRects();
    
    if (namedRects.empty()) {
        ImGui::TextDisabled("No named rectangles defined in texture");
        return;
    }
    
    // Build list of rect names
    std::vector<std::string> rectNames;
    rectNames.push_back("(default)");
    for (const auto& pair : namedRects) {
        rectNames.push_back(pair.first);
    }
    
    auto renderRectCombo = [&](const char* label, std::string& currentValue) {
        int currentIndex = 0;
        for (size_t i = 1; i < rectNames.size(); ++i) {
            if (currentValue == rectNames[i]) {
                currentIndex = (int)i;
                break;
            }
        }
        
        std::string comboItems;
        for (size_t i = 0; i < rectNames.size(); ++i) {
            if (i > 0) comboItems += '\0';
            comboItems += rectNames[i];
        }
        comboItems += '\0';
        
        int newIndex = currentIndex;
        if (ImGui::Combo(label, &newIndex, comboItems.c_str())) {
            if (newIndex == 0) {
                currentValue.clear();
            } else {
                currentValue = rectNames[newIndex];
            }
            return true;
        }
        return false;
    };
    
    ImGui::Text("Select texture rectangles for each part:");
    ImGui::Indent();
    
    if (renderRectCombo("Floor", grid.floorRectName)) {
        grid.markDirty();
    }
    if (renderRectCombo("Ceiling", grid.ceilingRectName)) {
        grid.markDirty();
    }
    if (renderRectCombo("External Walls", grid.extWallRectName)) {
        grid.markDirty();
    }
    if (renderRectCombo("Internal Walls", grid.intWallRectName)) {
        grid.markDirty();
    }
    if (renderRectCombo("Ext Door Frames", grid.extDoorFrameRectName)) {
        grid.markDirty();
    }
    if (renderRectCombo("Int Door Frames", grid.intDoorFrameRectName)) {
        grid.markDirty();
    }
    if (renderRectCombo("Ext Window Frames", grid.extWindowFrameRectName)) {
        grid.markDirty();
    }
    if (renderRectCombo("Int Window Frames", grid.intWindowFrameRectName)) {
        grid.markDirty();
    }
    if (renderRectCombo("Roof Top", grid.roofTopRectName)) {
        grid.markDirty();
    }
    if (renderRectCombo("Roof Side", grid.roofSideRectName)) {
        grid.markDirty();
    }
    
    ImGui::Unindent();
}
