-- HousingDecorGuide/UI/Projects/HDG_PlanPalette.lua
-- Plan-mode left-dock palette of room shapes. Click a card to spawn a new
-- "planned" room on the current floor at the first empty grid cell. The
-- new room has cell.locked = true and no Blizzard GUID (greenfield) — the
-- existing drag handlers in HDG_ArchitectCanvas can then move it around.

local _, privateDB = ...
local Atlas = privateDB.HDG_RoomShapeAtlas
local IDs   = privateDB.HDG_ProjectsIDs
local Store = privateDB.HDG_ProjectsStore

local M = {}

local PANEL_WIDTH = 130
local CARD_HEIGHT = 60
local CARD_PAD    = 4

local function _store()
    return _G.HousingDecorGuide and _G.HousingDecorGuide.Store
end

-- Spiral search outward from (0,0) for the first cell not occupied by any
-- room on the given floor. Cap at radius 12 — every house we've seen fits
-- in 8x8.
local function _firstEmptyCell(houseID, floor)
    local floorID = IDs.makeFloorID(houseID, floor)
    local occupied = {}
    if floorID then
        for _, e in ipairs(Store.GetRoomsForFloor(floorID)) do
            local c = e.room.cell
            if c and c.x and c.y then
                occupied[c.x .. ":" .. c.y] = true
            end
        end
    end

    local function _free(x, y) return not occupied[x .. ":" .. y] end
    if _free(0, 0) then return 0, 0 end
    for r = 1, 12 do
        for x = -r, r do
            for y = -r, r do
                -- ring boundary only
                if math.abs(x) == r or math.abs(y) == r then
                    if _free(x, y) then return x, y end
                end
            end
        end
    end
    return 0, 0  -- fallback (will collide; user can drag)
end

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

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

    local newID = Store.MintRoomID(floorID)
    if not newID then return end

    local cellX, cellY = _firstEmptyCell(houseID, floor)
    local store = _store()
    if not (store and store.UpsertProjectRoom) then return end

    -- Greenfield room: cell-locked, no Blizzard GUID, fingerprint empty.
    -- Doors come from the shape catalog so the orb-render path works.
    local doors = (Atlas and Atlas.GetDoors(shapeID)) or {}
    store:UpsertProjectRoom(newID, {
        shape = shapeID,
        cell  = { x = cellX, y = cellY, rotation = 0, locked = true },
        fingerprint = { doors = doors },
        doorCardinals     = doors,
        occupiedCardinals = {},   -- nothing connected yet
        capturedAt = time(),
        plannedOnly = true,       -- tag for distinguishing from real captured rooms
    })
end

function M:Create(parent)
    if self.frame then return self.frame end

    local f = CreateFrame("Frame", nil, parent)
    f:SetWidth(PANEL_WIDTH)
    f:SetPoint("TOPLEFT",     parent, "TOPLEFT",     0, -38)
    f:SetPoint("BOTTOMLEFT",  parent, "BOTTOMLEFT",  0,  10)
    f:SetFrameStrata("MEDIUM")
    f:Hide()

    local bg = f:CreateTexture(nil, "BACKGROUND")
    bg:SetAllPoints()
    bg:SetColorTexture(0.06, 0.13, 0.21, 0.92)

    local header = f:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
    header:SetPoint("TOPLEFT", 8, -6)
    header:SetText("|cffd6a9ffPlace shape|r")
    f.header = header

    local hint = f:CreateFontString(nil, "OVERLAY", "GameFontDisableSmall")
    hint:SetPoint("TOPLEFT", header, "BOTTOMLEFT", 0, -2)
    hint:SetText("Click |A:common-icon-forwardarrow:10:10|a drag")
    f.hint = hint

    -- Scrollable card list
    local scrollBox = CreateFrame("Frame", nil, f, "WowScrollBoxList")
    scrollBox:SetPoint("TOPLEFT",     6, -36)
    scrollBox:SetPoint("BOTTOMRIGHT", -16, 6)
    f.scrollBox = scrollBox

    local scrollBar = CreateFrame("EventFrame", nil, f, "MinimalScrollBar")
    scrollBar:SetPoint("TOPLEFT",    scrollBox, "TOPRIGHT", 2, 0)
    scrollBar:SetPoint("BOTTOMLEFT", scrollBox, "BOTTOMRIGHT", 2, 0)

    local view = CreateScrollBoxListLinearView(0, 0, 0, 0, CARD_PAD)
    view:SetElementExtent(CARD_HEIGHT)
    view:SetElementInitializer("Button", function(card, data)
        if not card._init then
            card._init = true
            card:SetHeight(CARD_HEIGHT)

            local cbg = card:CreateTexture(nil, "BACKGROUND")
            cbg:SetAllPoints()
            cbg:SetColorTexture(0.10, 0.18, 0.28, 0.9)
            card.bg = cbg

            local hover = card:CreateTexture(nil, "HIGHLIGHT")
            hover:SetAllPoints()
            hover:SetColorTexture(0.78, 0.50, 0.95, 0.20)

            card.icon = card:CreateTexture(nil, "ARTWORK")
            card.icon:SetSize(40, 40)
            card.icon:SetPoint("LEFT", 4, 0)

            card.label = card:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
            card.label:SetPoint("LEFT", card.icon, "RIGHT", 6, 6)
            card.label:SetPoint("RIGHT", card, "RIGHT", -4, 0)
            card.label:SetJustifyH("LEFT")
            card.label:SetWordWrap(false)

            card.cost = card:CreateFontString(nil, "OVERLAY", "GameFontDisableSmall")
            card.cost:SetPoint("LEFT", card.icon, "RIGHT", 6, -8)
            card.cost:SetJustifyH("LEFT")
        end

        card.icon:SetAtlas(Atlas.GetAtlas(data.shapeID), false)
        card.label:SetText(Atlas.GetLabel(data.shapeID))
        card.cost:SetText(string.format("|cffd6a93fcost %d|r", Atlas.GetBudget(data.shapeID)))

        card:SetScript("OnClick", function()
            _spawnRoom(data.shapeID, M._currentFloor or 1)
        end)
    end)
    ScrollUtil.InitScrollBoxListWithScrollBar(scrollBox, scrollBar, view)
    f.view = view

    -- Build dataProvider once — shape list is static.
    local provider = CreateDataProvider()
    for _, shapeID in ipairs(Atlas.ListShapes()) do
        provider:Insert({ shapeID = shapeID })
    end
    scrollBox:SetDataProvider(provider, ScrollBoxConstants.RetainScrollPosition)

    self.frame = f
    return f
end

function M:Show(floor)
    M._currentFloor = floor or 1
    if self.frame then self.frame:Show() end
end

function M:Hide()
    if self.frame then self.frame:Hide() end
end

function M:SetFloor(floor)
    M._currentFloor = floor or 1
end

privateDB.HDG_PlanPalette = M
