-- HousingDecorGuide/UI/Projects/HDG_ArchitectCanvas.lua
-- 2D blueprint canvas: renders rooms (housingroomicons atlases), connection lines,
-- open-door orbs. Reads layout from HDG_AutoLayout based on captured rooms.

local _, privateDB = ...

local IDs        = privateDB.HDG_ProjectsIDs
local Store      = privateDB.HDG_ProjectsStore
local AutoLayout = privateDB.HDG_AutoLayout
local ShapesDB   = privateDB.HDG_RoomShapesDB
local Atlas      = privateDB.HDG_RoomShapeAtlas   -- kept for backward compat; prefer ShapesDB

local M = {}

local CELL_SIZE = 48        -- pixels per cell at zoom = 1
local ORB_SIZE  = 12

-- HDG_EventBus lives on the HDG global (HDG.EventBus) and uses Register/Trigger
local function _EventBus()
    local g = _G.HousingDecorGuide
    return g and g.EventBus
end

local function _faction()
    local f = UnitFactionGroup("player")
    if f == "Alliance" then return "alliance" elseif f == "Horde" then return "horde" end
    return nil
end

local function _currentHouseID()
    local f = _faction()
    if not f then return nil end
    return "house:" .. f
end

-- Direction → unit cell offset for placing orbs on the room edge midpoint.
local DIR_OFFSET = {
    N = { 0, -0.5 },
    E = { 0.5, 0 },
    S = { 0, 0.5 },
    W = { -0.5, 0 },
}

function M:Create(parent)
    if self.frame then return self.frame end
    self.parent = parent
    self.zoom = 1
    self.currentFloor = 1
    self.pools = { rooms = {}, conns = {}, orbs = {} }
    self.onRoomClick = nil

    local frame = CreateFrame("Frame", nil, parent)
    frame:SetAllPoints(parent)

    -- Background
    local bg = frame:CreateTexture(nil, "BACKGROUND")
    bg:SetAllPoints()
    bg:SetColorTexture(0.04, 0.10, 0.18, 1)

    -- Inner host whose CENTER is the cell origin (cell 0,0 = host center)
    local host = CreateFrame("Frame", nil, frame)
    host:SetSize(1, 1)
    host:SetPoint("CENTER", frame, "CENTER", 0, 0)
    self.host = host
    self.frame = frame

    -- Subscribe to project state changes — refresh on capture or per-room change
    local bus = _EventBus()
    if bus and bus.Register then
        bus:Register("HDG_PROJECTS_TOPOLOGY_UPDATED", function() self:Refresh(self.currentFloor) end)
        bus:Register("HDG_PROJECTS_CAPTURE_COMPLETE", function() self:Refresh(self.currentFloor) end)
        bus:Register("HDG_PROJECT_ROOM_UPDATED",      function() self:Refresh(self.currentFloor) end)
    end

    return frame
end

function M:SetOnRoomClick(fn)
    self.onRoomClick = fn
end

local function _hideAllInPool(pool)
    if type(pool) == "table" then
        for _, f in pairs(pool) do
            if type(f) == "table" and f.Hide then f:Hide() end
        end
    end
end

function M:Refresh(floor)
    if not self.frame then return end
    floor = floor or self.currentFloor or 1
    self.currentFloor = floor

    local houseID = _currentHouseID()
    if not houseID then return end

    -- Hide previous visuals
    _hideAllInPool(self.pools.rooms)
    _hideAllInPool(self.pools.conns)
    _hideAllInPool(self.pools.orbs)

    local floorID = IDs.makeFloorID(houseID, floor)
    if not floorID then return end

    -- Build the layout-input map (include footprint so AutoLayout uses
    -- room-size-aware spacing — stops big rooms overlapping at adjacent cells).
    -- Prefer ShapesDB for atlas/cells; Atlas is kept as fallback.
    local entries = Store.GetRoomsForFloor(floorID)
    local roomsInput = {}
    for _, e in ipairs(entries) do
        local shape = e.room.shape
        local cells = (ShapesDB and ShapesDB.GetCells(shape)) or Atlas.GetCells(shape)
        roomsInput[e.id] = {
            shape             = shape,
            fingerprint       = e.room.fingerprint,
            occupiedCardinals = e.room.occupiedCardinals,
            rotation          = e.room.rotation,
            footprint         = cells,
        }
    end
    if not next(roomsInput) then return end

    local result = AutoLayout.compute(roomsInput)
    local cellPx = CELL_SIZE * self.zoom

    -- 1. Render rooms
    for roomID, info in pairs(result.layout) do
        local entry = roomsInput[roomID]
        local atlas = (ShapesDB and ShapesDB.GetAtlas(entry.shape)) or Atlas.GetAtlas(entry.shape)
        local cells = (ShapesDB and ShapesDB.GetCells(entry.shape)) or Atlas.GetCells(entry.shape)
        local w = (cells[1] or 1) * cellPx
        local h = (cells[2] or 1) * cellPx

        local btn = self.pools.rooms[roomID]
        if not btn then
            btn = CreateFrame("Button", nil, self.host)
            btn.tex = btn:CreateTexture(nil, "ARTWORK")
            btn.tex:SetAllPoints()
            btn.label = btn:CreateFontString(nil, "OVERLAY", "GameFontWhiteSmall")
            btn.label:SetPoint("CENTER")
            self.pools.rooms[roomID] = btn
        end

        -- Re-bind click handler each refresh in case onRoomClick changed
        local capturedID = roomID
        btn:SetScript("OnClick", function()
            if self.onRoomClick then self.onRoomClick(capturedID) end
        end)

        btn:SetSize(w - 4, h - 4)
        btn:ClearAllPoints()
        btn:SetPoint("CENTER", self.host, "CENTER",
            info.cell.x * cellPx,
            -info.cell.y * cellPx)   -- y- is N (up in screen space)

        if atlas then
            btn.tex:SetAtlas(atlas)
            btn.tex:SetVertexColor(1, 1, 1, 1)
        else
            btn.tex:SetTexture(nil)
            btn.tex:SetColorTexture(0.18, 0.30, 0.45, 1)
        end
        local parsed = IDs.parsePath(roomID) or {}
        btn.label:SetText(parsed.roomShortID or "")
        btn:Show()
    end

    -- 2. Render connections
    for i, c in ipairs(result.connections) do
        local fromCell = result.layout[c.fromID] and result.layout[c.fromID].cell
        local toCell   = result.layout[c.toID]   and result.layout[c.toID].cell
        if fromCell and toCell then
            local line = self.pools.conns[i]
            if not line then
                line = self.host:CreateLine(nil, "ARTWORK")
                line:SetThickness(2)
                line:SetColorTexture(0.55, 0.74, 0.88, 0.7)
                self.pools.conns[i] = line
            end
            line:SetStartPoint("CENTER", self.host, fromCell.x * cellPx, -fromCell.y * cellPx)
            line:SetEndPoint("CENTER",   self.host, toCell.x   * cellPx, -toCell.y   * cellPx)
            line:Show()
        end
    end

    -- 3. Render open-door orbs (for occupied doors that the layout did not connect)
    local orbIdx = 0
    for roomID, entry in pairs(roomsInput) do
        local layoutInfo = result.layout[roomID]
        if layoutInfo then
            local fp = entry.fingerprint or {}
            local total = {}
            for _, d in ipairs(fp.occupiedDoors or {}) do total[d] = (total[d] or 0) + 1 end
            local used = {}
            for _, c in ipairs(result.connections) do
                if c.fromID == roomID then used[c.fromDir] = (used[c.fromDir] or 0) + 1 end
                if c.toID   == roomID then used[c.toDir]   = (used[c.toDir]   or 0) + 1 end
            end
            for dir, n in pairs(total) do
                local u = used[dir] or 0
                local unfilled = n - u
                for _ = 1, unfilled do
                    orbIdx = orbIdx + 1
                    local orb = self.pools.orbs[orbIdx]
                    if not orb then
                        orb = self.host:CreateTexture(nil, "OVERLAY")
                        orb:SetSize(ORB_SIZE, ORB_SIZE)
                        orb:SetColorTexture(0.96, 0.80, 0.36, 1)
                        self.pools.orbs[orbIdx] = orb
                    end
                    local off = DIR_OFFSET[dir] or { 0, 0 }
                    orb:ClearAllPoints()
                    orb:SetPoint("CENTER", self.host, "CENTER",
                        (layoutInfo.cell.x + off[1]) * cellPx,
                        -(layoutInfo.cell.y + off[2]) * cellPx)
                    orb:Show()
                end
            end
        end
    end
end

privateDB.HDG_ArchitectCanvas = M
