--[[
============================================================================
UI/TransmogUI/Slots.lua  (added in v14.9.0 — Audit Batch 3 Part 1)
============================================================================

Slot-button rendering and slot-click logic for the TransmogUI orchestrator.
Owner-pattern: each method takes `owner` (the TUI orchestrator) as first
argument and accesses TUI state via owner.frame, owner.pendingTransmogs,
etc. The orchestrator keeps thin delegator methods so all existing call
sites (self:UpdateSlotButtonIcons, self:SelectSlot, etc.) keep working.

Methods owned here:
  GetDefaultSlotIcon  — slot-icon path lookup
  ToggleSlotHide      — flip a slot between transmogged and "hide this slot"
  UpdateSlotButtonIcons — sync all 13 slot buttons against pendingTransmogs
  SelectSlot          — user clicked a slot button; switch browser to its
                        category and update labels
  SelectAppearance    — user clicked an item in the browser; queue it as
                        the pending transmog for the currently-selected slot

Methods kept on TUI itself (used cross-module):
  GetCachedItem       — generic item-cache helper (called from many places)
  GetPlayerArmorType  — used by Sets, Capture, and others

Closure / shadowing notes (v12.63 lessons):
  - All 5 methods are pure object-methods: `self` is always the calling
    instance (which is TUI when delegators dispatch). No `function(self,...)`
    frame scripts moved here — those stayed in Frame.lua/CategoryBar.lua/etc.
  - No file-local upvalue references to `TUI` from within these methods,
    so the move is mechanical: rename `self` to `owner` in the signatures.
============================================================================
]]--
local ADDON_NAME, NS = ...
local ETB = NS.ETB
NS.ETB.TransmogUI = NS.ETB.TransmogUI or {}
NS.ETB.TransmogUI.Slots = NS.ETB.TransmogUI.Slots or {}
local Slots = NS.ETB.TransmogUI.Slots

-- =============================================================================
-- SLOT ICON
-- =============================================================================

function Slots:GetDefaultSlotIcon(owner, invSlot)
    local slotIcons = {
        [1]  = "Interface\\PaperDoll\\UI-PaperDoll-Slot-Head",
        [3]  = "Interface\\PaperDoll\\UI-PaperDoll-Slot-Shoulder",
        [4]  = "Interface\\PaperDoll\\UI-PaperDoll-Slot-Shirt",
        [5]  = "Interface\\PaperDoll\\UI-PaperDoll-Slot-Chest",
        [6]  = "Interface\\PaperDoll\\UI-PaperDoll-Slot-Waist",
        [7]  = "Interface\\PaperDoll\\UI-PaperDoll-Slot-Legs",
        [8]  = "Interface\\PaperDoll\\UI-PaperDoll-Slot-Feet",
        [9]  = "Interface\\PaperDoll\\UI-PaperDoll-Slot-Wrists",
        [10] = "Interface\\PaperDoll\\UI-PaperDoll-Slot-Hands",
        [15] = "Interface\\PaperDoll\\UI-PaperDoll-Slot-Chest",  -- Back uses chest icon
        [16] = "Interface\\PaperDoll\\UI-PaperDoll-Slot-MainHand",
        [17] = "Interface\\PaperDoll\\UI-PaperDoll-Slot-SecondaryHand",
        [19] = "Interface\\PaperDoll\\UI-PaperDoll-Slot-Tabard",
    }
    return slotIcons[invSlot] or "Interface\\PaperDoll\\UI-Backpack-EmptySlot"
end

-- =============================================================================
-- TOGGLE SLOT HIDE
-- =============================================================================
-- Flip a slot between "has a transmog pending" and "set this slot to hidden
-- (no visible item)". Pushes change to Blizzard's pending state.

function Slots:ToggleSlotHide(owner, invSlot)
    local btn = owner.frame.slotButtons[invSlot]
    if not btn then return end

    -- v15.7.3: MoP 5.4.8 does not support hiding Tabard (slot 19) or Shirt
    -- (slot 4) via the transmog API. The "hidden appearance" entries that
    -- C_TransmogCollection.GetCategoryAppearances returns for armor slots
    -- (categories 1-11 except 5/6) do not exist for Tabard/Shirt categories
    -- on this client version — that feature shipped with Legion patch 7.1.0
    -- (October 2016), two years after MoP 5.4.8.
    --
    -- Without a hidden sourceID to apply, the three-method fallback chain
    -- in Apply:CallSetPendingHidden silently fails. Reject the action up
    -- front so the user gets a clear explanation instead of confusing UI
    -- state. They can still hide the tabard via WoW's interface toggle
    -- (no equivalent for shirt; players unequip if they don't want to wear).
    if invSlot == 19 or invSlot == 4 then
        local slotLabel = (invSlot == 19) and "Tabard" or "Shirt"
        ETB:Print(string.format(
            "|cffff9966Cannot hide %s:|r MoP Classic (5.4.8) does not support hiding the %s slot via transmog. " ..
            "This feature was added to retail WoW in patch 7.1.0 (Legion). " ..
            (invSlot == 19 and "Unequip the tabard to remove it from view." or "Unequip the shirt to remove it from view."),
            slotLabel, slotLabel))
        return
    end

    local pending = owner.pendingTransmogs[invSlot]

    if pending and pending.isHiddenSlot then
        -- Currently hidden, remove the hide
        owner.pendingTransmogs[invSlot] = nil
        btn.isHidden = false
        btn.hiddenBorder:Hide()
        btn.pendingBorder:Hide()
        btn.pendingInner:Hide()
        btn.icon:SetTexture(self:GetDefaultSlotIcon(owner, invSlot))
        btn.icon:SetDesaturated(false)
        btn:SetBackdropBorderColor(0.4, 0.4, 0.4, 1)

        -- Restore on model (avoid SetUnit which causes graphics reset)
        if owner.frame.model then
            owner.frame.model:Dress()
            for _, pend in pairs(owner.pendingTransmogs) do
                if pend.itemID and not pend.isHiddenSlot then
                    owner.frame.model:TryOn("item:" .. pend.itemID)
                end
            end
        end

        ETB:Debug("TransmogUI", string.format("%s visible", btn.slotName))
    else
        -- Set to hidden
        owner.pendingTransmogs[invSlot] = {
            isHiddenSlot = true,
            name = "Hidden",
            icon = "Interface\\Icons\\INV_Misc_QuestionMark",
        }
        btn.isHidden = true
        btn.hiddenBorder:Show()
        btn.pendingBorder:Hide()
        btn.pendingInner:Hide()
        btn.icon:SetTexture("Interface\\Icons\\Spell_Shadow_SacrificialShield")
        btn.icon:SetDesaturated(true)
        btn:SetBackdropBorderColor(0.8, 0.2, 0.2, 1)

        ETB:Debug("TransmogUI", string.format("%s hidden", btn.slotName))
    end

    -- Push the change to Blizzard so both UIs stay in sync
    owner:PushSlotToBlizzard(invSlot)
    owner:UpdateCost()
end

-- =============================================================================
-- UPDATE SLOT BUTTON ICONS
-- =============================================================================
-- Called whenever pendingTransmogs changes — walks all 13 slot buttons and
-- syncs their visual state (icon, borders, desaturation) to match.

function Slots:UpdateSlotButtonIcons(owner)
    if not owner.frame or not owner.frame.slotButtons then return end

    for invSlot, btn in pairs(owner.frame.slotButtons) do
        local pending = owner.pendingTransmogs[invSlot]

        if pending then
            if pending.isHiddenSlot then
                -- Slot is set to hidden
                btn.isHidden = true
                btn.hiddenBorder:Show()
                btn.pendingBorder:Hide()
                btn.pendingInner:Hide()
                btn.icon:SetTexture("Interface\\Icons\\Spell_Shadow_SacrificialShield")
                btn.icon:SetDesaturated(true)
                btn:SetBackdropBorderColor(0.8, 0.2, 0.2, 1)
            else
                -- Slot has a transmog selected
                btn.isHidden = false
                btn.hiddenBorder:Hide()
                btn.pendingBorder:Show()
                btn.pendingInner:Show()
                btn.icon:SetTexture(pending.icon or self:GetDefaultSlotIcon(owner, invSlot))
                btn.icon:SetDesaturated(false)
                btn:SetBackdropBorderColor(1, 0.82, 0, 1)
            end
        else
            -- No pending change
            btn.isHidden = false
            btn.hiddenBorder:Hide()
            btn.pendingBorder:Hide()
            btn.pendingInner:Hide()
            btn.icon:SetTexture(self:GetDefaultSlotIcon(owner, invSlot))
            btn.icon:SetDesaturated(false)
            btn:SetBackdropBorderColor(0.4, 0.4, 0.4, 1)
        end
    end
end

-- =============================================================================
-- SELECT SLOT
-- =============================================================================
-- User clicked a slot button (head/chest/etc). Switch the browser to show
-- appearances for that slot's category, update tab highlighting, refresh.

function Slots:SelectSlot(owner, invSlot)
    owner.selectedSlot = invSlot
    owner.selectedTab = "appearances"

    local slotName, categoryIDFromSlot = "Unknown", nil
    for _, slot in ipairs(owner.SLOTS or {}) do
        if slot.invSlot == invSlot then
            slotName = slot.name
            categoryIDFromSlot = slot.categoryID
            break
        end
    end

    owner.selectedCategoryID = categoryIDFromSlot
    owner:UpdateCategoryBarHighlight()
    owner:UpdateCurrentViewingLabel()

    owner.frame.browserPanel.title:SetText("|cffffd100" .. slotName .. " Appearances|r")
    owner.frame.browserPanel.appearancesTab.text:SetText("|cff00ff00Appearances|r")
    owner.frame.browserPanel.appearancesTab.underline:Show()
    owner.frame.browserPanel.setsTab.text:SetText("|cff888888Sets|r")
    owner.frame.browserPanel.setsTab.underline:Hide()
    if owner.frame.browserPanel.incompleteTab then
        owner.frame.browserPanel.incompleteTab.text:SetText("|cff888888Incomplete|r")
        owner.frame.browserPanel.incompleteTab.underline:Hide()
    end

    owner:RefreshBrowser()
end

-- =============================================================================
-- SELECT APPEARANCE
-- =============================================================================
-- User clicked an item in the browser. Queue it as the pending transmog for
-- the currently-selected slot, update the model preview, push to Blizzard.

function Slots:SelectAppearance(owner, appearance)
    if not appearance or not owner.selectedSlot then return end

    -- Handle "Hide Appearance" option
    if appearance.isHidden then
        -- v15.7.3: same guard as ToggleSlotHide — MoP 5.4.8 cannot hide
        -- Tabard (19) or Shirt (4) via the transmog API. See ToggleSlotHide
        -- for full explanation.
        if owner.selectedSlot == 19 or owner.selectedSlot == 4 then
            local slotLabel = (owner.selectedSlot == 19) and "Tabard" or "Shirt"
            ETB:Print(string.format(
                "|cffff9966Cannot hide %s:|r MoP Classic (5.4.8) does not support hiding the %s slot via transmog. " ..
                "Unequip the item to remove it from view.",
                slotLabel, slotLabel))
            return
        end

        -- Always set as hidden slot — Blizzard sync uses ToggleOff pending type
        owner.pendingTransmogs[owner.selectedSlot] = {
            isHiddenSlot = true,
            name = appearance.name or "Hidden",
            icon = appearance.icon or "Interface\\Icons\\Spell_Shadow_SacrificialShield",
        }

        -- Update model: redress then re-apply remaining non-hidden pending items
        if owner.frame.model then
            owner.frame.model:Dress()
            for _, pending in pairs(owner.pendingTransmogs) do
                if pending.itemID and not pending.isHiddenSlot then
                    owner.frame.model:TryOn("item:" .. pending.itemID)
                end
            end
        end

        owner:UpdateSlotButtonIcons()
        owner:PushSlotToBlizzard(owner.selectedSlot)
        owner:UpdateCost()
        return
    end

    -- Get icon - try multiple sources to ensure we have one
    local icon = appearance.icon
    if (not icon or icon == "" or icon == "Interface\\Icons\\INV_Misc_QuestionMark") and appearance.itemID then
        icon = GetItemIcon(appearance.itemID) or "Interface\\Icons\\INV_Misc_QuestionMark"
    end

    -- Apply to model
    if owner.frame and owner.frame.model and appearance.itemID then
        owner.frame.model:TryOn("item:" .. appearance.itemID)
    end

    -- Store pending transmog
    owner.pendingTransmogs[owner.selectedSlot] = {
        sourceID = appearance.sourceID,
        itemID = appearance.itemID,
        name = appearance.name,
        icon = icon,
    }

    -- Direct slot button update
    local btn = owner.frame.slotButtons[owner.selectedSlot]
    if btn then
        btn.icon:SetTexture(icon)
        btn.pendingBorder:Show()
        btn.pendingInner:Show()
        btn:SetBackdropBorderColor(1, 0.82, 0, 1)  -- Gold border
    end

    if appearance.sourceID and appearance.itemID then
        owner.itemIDToSourceID[appearance.itemID] = appearance.sourceID
    end

    -- Push this slot to Blizzard API so both UIs stay in sync
    owner:PushSlotToBlizzard(owner.selectedSlot)

    owner:UpdateCost()
end
