#include "RoomEditor.hpp"
#include "../components/CellGrid.hpp"
#include "../components/EntityName.hpp"
#include "../systems/FurnitureLibrary.hpp"
#include <imgui.h>
#include <algorithm>
#include <set>

bool RoomEditor::renderComponent(flecs::entity entity, RoomComponent& room)
{
    bool modified = false;
    
    // Ensure room has a persistent ID
    room.ensurePersistentId(entity.id());
    
    if (ImGui::CollapsingHeader("Room", ImGuiTreeNodeFlags_DefaultOpen)) {
        ImGui::Indent();
        
        // Display room identification info
        ImGui::TextDisabled("Entity ID: %lu", entity.id());
        ImGui::TextDisabled("Persistent ID: %s", room.persistentId.c_str());
        ImGui::Separator();
        
        ImGui::Text("Room Size: %dx%dx%d", room.getSizeX(), room.getSizeY(), room.getSizeZ());
        
        int minPos[3] = { room.minX, room.minY, room.minZ };
        if (ImGui::InputInt3("Min (X/Y/Z)", minPos)) {
            room.minX = minPos[0];
            room.minY = minPos[1];
            room.minZ = minPos[2];
            modified = true;
        }
        
        int maxPos[3] = { room.maxX, room.maxY, room.maxZ };
        if (ImGui::InputInt3("Max (X/Y/Z)", maxPos)) {
            room.maxX = maxPos[0];
            room.maxY = maxPos[1];
            room.maxZ = maxPos[2];
            modified = true;
        }
        
        // Creation options
        if (ImGui::Checkbox("Create Floor", &room.createFloor)) modified = true;
        if (ImGui::Checkbox("Create Ceiling", &room.createCeiling)) modified = true;
        if (ImGui::Checkbox("Create Interior Walls", &room.createInteriorWalls)) modified = true;
        if (ImGui::Checkbox("Create Windows", &room.createWindows)) modified = true;
        if (ImGui::Checkbox("Fill Room with Furniture", &room.fillRoomWithFurniture)) modified = true;
        int seed = static_cast<int>(room.furnitureSeed);
        if (ImGui::InputInt("Furniture Seed", &seed)) {
            room.furnitureSeed = static_cast<unsigned int>(seed);
            modified = true;
        }
        if (ImGui::DragFloat("Furniture Y Offset", &room.furnitureYOffset, 0.01f, 0.0f, 0.5f)) {
            modified = true;
        }
        ImGui::TextDisabled("Change seed for different furniture arrangement");
        ImGui::TextDisabled("(Windows are created after all doors)");
        
        ImGui::Separator();
        
        char roomType[128] = {0};
        strncpy(roomType, room.roomType.c_str(), sizeof(roomType) - 1);
        if (ImGui::InputText("Room Type", roomType, sizeof(roomType))) {
            room.roomType = roomType;
            modified = true;
        }
        
        // Tags
        std::string tagsStr;
        for (size_t i = 0; i < room.tags.size(); ++i) {
            if (i > 0) tagsStr += ", ";
            tagsStr += room.tags[i];
        }
        char tagsBuf[256] = {0};
        strncpy(tagsBuf, tagsStr.c_str(), sizeof(tagsBuf) - 1);
        if (ImGui::InputText("Tags", tagsBuf, sizeof(tagsBuf))) {
            room.tags.clear();
            std::string newTags(tagsBuf);
            size_t start = 0;
            size_t end = newTags.find(',');
            while (end != std::string::npos) {
                std::string tag = newTags.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()) room.tags.push_back(tag);
                start = end + 1;
                end = newTags.find(',', start);
            }
            std::string lastTag = newTags.substr(start);
            lastTag.erase(0, lastTag.find_first_not_of(" \t"));
            lastTag.erase(lastTag.find_last_not_of(" \t") + 1);
            if (!lastTag.empty()) room.tags.push_back(lastTag);
            modified = true;
        }

        // Validate that furniture exists for these tags
        if (!room.tags.empty()) {
            FurnitureLibrary::getInstance().loadAll();
            auto matches = FurnitureLibrary::getInstance().findByTags(room.tags, {});
            if (matches.empty()) {
                ImGui::TextColored(ImVec4(1.0f, 0.3f, 0.3f, 1.0f),
                    "Warning: No furniture found for these tags");
            } else {
                ImGui::TextDisabled("%zu furniture item(s) match", matches.size());
            }
        }

        if (ImGui::CollapsingHeader("Available Furniture", ImGuiTreeNodeFlags_None)) {
            ImGui::Indent();
            FurnitureLibrary::getInstance().loadAll();
            const auto& defs = FurnitureLibrary::getInstance().getDefinitions();
            if (defs.empty()) {
                ImGui::TextDisabled("No furniture definitions loaded");
            } else {
                // Build a sorted set of all tags
                std::set<std::string> allTags;
                for (const auto& def : defs) {
                    for (const auto& tag : def.tags) {
                        allTags.insert(tag);
                    }
                }
                ImGui::TextDisabled("All tags:");
                std::string tagList;
                for (const auto& tag : allTags) {
                    if (!tagList.empty()) tagList += ", ";
                    tagList += tag;
                }
                ImGui::TextWrapped("%s", tagList.c_str());
                ImGui::Separator();

                for (const auto& def : defs) {
                    std::string tagStr;
                    for (size_t i = 0; i < def.tags.size(); ++i) {
                        if (i > 0) tagStr += ", ";
                        tagStr += def.tags[i];
                    }
                    ImGui::BulletText("%s [%s]", def.name.c_str(), tagStr.c_str());
                }
            }
            ImGui::Unindent();
        }
        
        ImGui::Unindent();
    }
    
    // Exits Section
    if (ImGui::CollapsingHeader("Exits (To Outside)", ImGuiTreeNodeFlags_DefaultOpen)) {
        ImGui::Indent();
        
        ImGui::Text("Create exit doors to outside:");
        ImGui::TextDisabled("(Internal doors on outside-facing walls)");
        ImGui::TextDisabled("(Converted to exterior by Exterior Generation)");
        
        const char* sideNames[] = { "Z- (North)", "Z+ (South)", "X- (West)", "X+ (East)" };
        
        for (int i = 0; i < 4; i++) {
            ImGui::PushID(i);
            if (ImGui::Checkbox(sideNames[i], &room.exits[i])) {
                modified = true;
            }
            ImGui::PopID();
        }
        
        // Quick presets
        ImGui::Separator();
        if (ImGui::Button("All Exits")) {
            room.setAllExits(true);
            modified = true;
        }
        ImGui::SameLine();
        if (ImGui::Button("No Exits")) {
            room.setAllExits(false);
            modified = true;
        }
        
        ImGui::Unindent();
    }
    
    // Connections Section
    if (ImGui::CollapsingHeader("Connections", ImGuiTreeNodeFlags_DefaultOpen)) {
        ImGui::Indent();
        
        // Build a map of persistent ID -> room info for displaying connections
        std::unordered_map<std::string, flecs::entity> roomMap;
        std::unordered_map<std::string, std::string> roomLabels;
        flecs::entity parent = entity.parent();
        if (parent.is_alive()) {
            parent.children([&](flecs::entity child) {
                if (child.has<RoomComponent>()) {
                    const auto& r = child.get<RoomComponent>();
                    std::string label = formatRoomLabel(child, r);
                    roomMap[r.persistentId] = child;
                    roomLabels[r.persistentId] = label;
                }
            });
        }
        
        ImGui::Text("Connected to %zu room(s):", room.connectedRoomIds.size());
        
        // List current connections with remove buttons
        int removeIndex = -1;
        float contentRight = ImGui::GetCursorPosX() + ImGui::GetContentRegionAvail().x;
        float maxRowRight = 0.0f;
        for (size_t i = 0; i < room.connectedRoomIds.size(); i++) {
            const std::string& connectedId = room.connectedRoomIds[i];
            ImGui::PushID((int)i);
            
            auto it = roomMap.find(connectedId);
            if (it != roomMap.end()) {
                // Check if rooms are actually adjacent
                const auto& otherRoom = it->second.get<RoomComponent>();
                bool isAdjacent = areRoomsAdjacent(room, otherRoom);
                
                if (isAdjacent) {
                    ImGui::Text("  %zu: %s", i + 1, roomLabels[connectedId].c_str());
                } else {
                    // Mark non-adjacent connections in yellow
                    ImGui::TextColored(ImVec4(1.0f, 0.8f, 0.0f, 1.0f), 
                        "  %zu: %s (Not adjacent - will not create door)", 
                        i + 1, roomLabels[connectedId].c_str());
                }
            } else {
                ImGui::TextColored(ImVec4(1.0f, 0.0f, 0.0f, 1.0f), 
                    "  %zu: (Invalid room ID: %s)", i + 1, connectedId.c_str());
            }
            
            ImGui::SameLine();
            if (ImGui::SmallButton("Remove")) {
                removeIndex = (int)i;
                modified = true;
            }
            
            maxRowRight = std::max(maxRowRight,
                ImGui::GetItemRectMax().x - ImGui::GetWindowPos().x);
            ImGui::PopID();
        }
        
        /* Ensure the horizontal scrollbar thumb appears when connection
         * rows overflow the panel width. ImGui culls off-screen widgets,
         * so we explicitly extend the content width with a dummy. */
        float savedX = ImGui::GetCursorPosX();
        float savedY = ImGui::GetCursorPosY();
        if (maxRowRight > contentRight) {
                ImGui::SetCursorPosX(0.0f);
                ImGui::Dummy(ImVec2(maxRowRight + 1.0f, 0.0f));
                ImGui::SetCursorPos(ImVec2(savedX, savedY));
        }
        
        if (removeIndex >= 0) {
            // Remove from this room
            std::string removedId = room.connectedRoomIds[removeIndex];
            room.connectedRoomIds.erase(room.connectedRoomIds.begin() + removeIndex);
            
            // Also remove this room from the other room's list (bidirectional)
            auto it = roomMap.find(removedId);
            if (it != roomMap.end() && it->second.is_alive() && it->second.has<RoomComponent>()) {
                auto& otherRoom = it->second.get_mut<RoomComponent>();
                otherRoom.removeConnection(room.persistentId);
            }
        }
        
        ImGui::Separator();
        
        // Add connection section
        ImGui::Text("Add Connection:");
        
        // Find all available rooms in the same parent
        std::vector<flecs::entity> availableRooms;
        std::vector<std::string> availableRoomLabels;
        
        if (parent.is_alive()) {
            parent.children([&](flecs::entity child) {
                if (child.has<RoomComponent>() && child != entity) {
                    const auto& r = child.get<RoomComponent>();
                    // Check if not already connected
                    if (!room.isConnectedTo(r.persistentId)) {
                        availableRooms.push_back(child);
                        availableRoomLabels.push_back(formatRoomLabel(child, r));
                    }
                }
            });
        }
        
        if (availableRooms.empty()) {
            ImGui::TextDisabled("  No available rooms to connect");
        } else {
            // Use non-static index to avoid flickering when list changes
            // Store index in a map keyed by entity ID
            flecs::entity_t entityId = entity.id();
            if (m_selectedRoomIndex.find(entityId) == m_selectedRoomIndex.end()) {
                m_selectedRoomIndex[entityId] = 0;
            }
            int& selectedRoomIdx = m_selectedRoomIndex[entityId];
            if (selectedRoomIdx >= (int)availableRooms.size()) selectedRoomIdx = 0;
            
            // Build combo items using ImGui style (null-terminated strings)
            // Each item is terminated by \0, and the list is terminated by an extra \0
            std::vector<char> comboItems;
            for (size_t i = 0; i < availableRoomLabels.size(); i++) {
                for (char c : availableRoomLabels[i]) {
                    comboItems.push_back(c);
                }
                comboItems.push_back('\0'); // End of this item
            }
            comboItems.push_back('\0'); // End of list
            
            ImGui::PushID("add_conn");
            if (ImGui::Combo("Room", &selectedRoomIdx, comboItems.data())) {
                // Selection changed
            }
            
            ImGui::SameLine();
            if (ImGui::Button("Connect")) {
                flecs::entity selectedRoom = availableRooms[selectedRoomIdx];
                const auto& selectedRoomComp = selectedRoom.get<RoomComponent>();
                
                // Add bidirectional connection using persistent IDs
                room.addConnection(selectedRoomComp.persistentId);
                auto& otherRoom = selectedRoom.get_mut<RoomComponent>();
                otherRoom.addConnection(room.persistentId);
                
                modified = true;
            }
            ImGui::PopID();
        }
        
        ImGui::Unindent();
    }
    
    if (modified) {
        room.markDirty();
    }
    
    return modified;
}

std::string RoomEditor::formatRoomLabel(flecs::entity entity, const RoomComponent& room)
{
    // Format: "Name [E:entityId P:persistentId] (Type)"
    std::string label;
    
    // Try to get entity name if available
    if (entity.has<EntityNameComponent>()) {
        label = entity.get<EntityNameComponent>().name;
    }
    
    if (label.empty()) {
        label = room.roomType.empty() ? "Unnamed" : room.roomType;
    }
    
    // Add entity ID and persistent ID
    label += " [E:" + std::to_string(entity.id()) + " P:" + room.persistentId.substr(0, 8) + "]";
    
    // Add room type if different from name
    if (!room.roomType.empty() && label.find(room.roomType) == std::string::npos) {
        label += " (" + room.roomType + ")";
    }
    
    return label;
}

bool RoomEditor::areRoomsAdjacent(const RoomComponent& roomA, const RoomComponent& roomB)
{
    // Two rooms are adjacent if they share at least one edge
    // Check if roomB is directly adjacent to roomA on any side
    
    // Check Z- side of roomA (is roomB at z = roomA.minZ - 1 with overlapping X?)
    if (roomB.maxZ == roomA.minZ && roomB.maxX > roomA.minX && roomB.minX < roomA.maxX) return true;
    
    // Check Z+ side of roomA
    if (roomB.minZ == roomA.maxZ && roomB.maxX > roomA.minX && roomB.minX < roomA.maxX) return true;
    
    // Check X- side of roomA
    if (roomB.maxX == roomA.minX && roomB.maxZ > roomA.minZ && roomB.minZ < roomA.maxZ) return true;
    
    // Check X+ side of roomA
    if (roomB.minX == roomA.maxX && roomB.maxZ > roomA.minZ && roomB.minZ < roomA.maxZ) return true;
    
    return false;
}
