EbonholdHub.GearView = {}

local UI = EbonholdHub.UI
local C  = UI.Colors
local ST = EbonholdHub.SiteTheme
local SW = EbonholdHub.SiteWidgets
local SC = ST and ST.C
local SL = ST and ST.Layout
local EL = EbonholdHub.EquipmentLoadout
local AD = EbonholdHub.AffixData
local IC = EbonholdHub.ItemCatalog

local HEADER_PAD  = 6
local SET_ROW_H   = EbonholdHub.GearSetStrip and EbonholdHub.GearSetStrip.RowHeight() or 26
local ACTION_H    = 24
local HEADER_H    = HEADER_PAD + SET_ROW_H + 4 + ACTION_H + HEADER_PAD
local GAP         = 8
local SLOT_SIZE   = 40
local DOLL_W      = 340

local viewFrame
local headerActions, setStrip
local bodyFrame, leftPanel, rightPanel
local dollHolder
local gearListScroll, gearListChild
local slotButtons = {}

local function ItemQualityColor(quality)
    if GetItemQualityColor then
        local r, g, b = GetItemQualityColor(quality or 0)
        if r then return r, g, b end
    end
    return 0.9, 0.9, 0.9
end

local function RefreshGearList()
    if not gearListChild then return end
    local listW = gearListScroll and gearListScroll:GetWidth() or 200
    if listW <= 0 then listW = 200 end
    gearListChild:SetWidth(listW)

    if gearListChild._rows then
        for _, row in ipairs(gearListChild._rows) do
            row:Hide()
            row:SetParent(nil)
        end
    end
    gearListChild._rows = {}

    local rowY = 0
    for _, slotDef in ipairs(AD.SLOTS) do
        local entry = EL.GetSlot(slotDef.key)
        if entry and IC then IC.EnrichEntry(entry) end
        local filled = entry and (entry.name or entry.itemId)
        local row = SW.CreateListRow(gearListChild, {
            slotLabel      = slotDef.label,
            invSlot        = slotDef.invSlot,
            name           = filled and (entry.name or ("Item " .. tostring(entry.itemId))) or "—",
            quality        = entry and entry.quality,
            texture        = entry and entry.texture,
            itemId         = entry and entry.itemId,
            filled         = filled,
            iconSize       = 24,
            height         = 32,
            slotLabelWidth = 52,
            nameWidth      = listW,
        })
        row:SetPoint("TOPLEFT", 0, -rowY)
        row:SetPoint("RIGHT", 0, 0)
        row:SetAlpha(filled and 1 or 0.45)
        row:EnableMouse(true)
        row:SetScript("OnMouseDown", function()
            EbonholdHub.ItemPicker.Show(function(itemEntry)
                if itemEntry then
                    EL.SetSlot(slotDef.key, itemEntry)
                    -- RefreshAll deferred via closure below
                    if viewFrame and viewFrame._refreshAll then
                        viewFrame._refreshAll()
                    end
                end
            end, slotDef)
        end)
        row:SetScript("OnMouseUp", function(_, button)
            if button == "RightButton" then
                EL.SetSlot(slotDef.key, nil)
                if viewFrame and viewFrame._refreshAll then
                    viewFrame._refreshAll()
                end
            end
        end)
        row:SetScript("OnEnter", function()
            GameTooltip:SetOwner(row, "ANCHOR_RIGHT")
            GameTooltip:ClearLines()
            GameTooltip:AddLine(slotDef.label, 1, 0.82, 0)
            if entry and entry.itemId then
                local hyperlink = IC and IC.GetItemHyperlink(entry) or ("item:" .. entry.itemId)
                GameTooltip:SetHyperlink(hyperlink)
                GameTooltip:AddLine("Right-click to clear", 0.5, 0.5, 0.5)
            elseif filled then
                local r, g, b = ItemQualityColor(entry.quality)
                GameTooltip:AddLine(entry.name, r, g, b)
                GameTooltip:AddLine("Right-click to clear", 0.5, 0.5, 0.5)
            else
                GameTooltip:AddLine("Click to assign an item", 0.6, 0.6, 0.6)
            end
            GameTooltip:Show()
        end)
        row:SetScript("OnLeave", function() GameTooltip:Hide() end)
        gearListChild._rows[#gearListChild._rows + 1] = row
        rowY = rowY + row:GetHeight()
    end
    gearListChild:SetHeight(math.max(1, rowY))
    if gearListScroll and gearListScroll.UpdateThumb then
        gearListScroll.UpdateThumb()
    end
end

local function WireSlotTooltip(btn, slotDef)
    btn:SetScript("OnEnter", function(self)
        GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
        GameTooltip:ClearLines()
        local entry = EL.GetSlot(slotDef.key)
        if entry and entry.itemId then
            if IC then IC.EnrichEntry(entry) end
            local hyperlink = IC and IC.GetItemHyperlink(entry)
            if hyperlink then
                GameTooltip:SetHyperlink(hyperlink)
            else
                GameTooltip:SetHyperlink("item:" .. entry.itemId)
            end
            GameTooltip:AddLine("Right-click to clear", 0.5, 0.5, 0.5)
        elseif entry and entry.name then
            GameTooltip:AddLine(slotDef.label, 1, 0.82, 0)
            local r, g, b = ItemQualityColor(entry.quality)
            GameTooltip:AddLine(entry.name, r, g, b)
            GameTooltip:AddLine("Right-click to clear", 0.5, 0.5, 0.5)
        else
            GameTooltip:AddLine(slotDef.label, 1, 0.82, 0)
            GameTooltip:AddLine("Click to assign an item", 0.6, 0.6, 0.6)
        end
        GameTooltip:Show()
    end)
    btn:SetScript("OnLeave", function() GameTooltip:Hide() end)
end

local function RefreshSlotButton(btn, slotDef)
    local entry = EL.GetSlot(slotDef.key)
    if entry and entry.name then
        local tex = EL.GetItemIcon(entry)
        if tex then
            btn.icon:SetTexture(tex)
            btn.icon:SetVertexColor(1, 1, 1)
        else
            btn.icon:SetTexture(AD.GetSlotTexture(slotDef.invSlot))
            btn.icon:SetVertexColor(0.85, 0.85, 0.85)
        end
        btn._empty:Hide()
    else
        btn.icon:SetTexture(AD.GetSlotTexture(slotDef.invSlot))
        btn.icon:SetVertexColor(0.55, 0.55, 0.55)
        btn._empty:Show()
    end
end

local function RefreshAll()
    for _, slotDef in ipairs(AD.SLOTS) do
        local btn = slotButtons[slotDef.key]
        if btn then RefreshSlotButton(btn, slotDef) end
    end
    RefreshGearList()
    if dollHolder then
        EbonholdHub.AffixDoll.Refresh(dollHolder)
    end
    if IC then
        local toEnrich = {}
        for _, slotDef in ipairs(AD.SLOTS) do
            local entry = EL.GetSlot(slotDef.key)
            if entry then toEnrich[#toEnrich + 1] = entry end
        end
        if #toEnrich > 0 then
            IC.EnrichList(toEnrich, function()
                if viewFrame and viewFrame:IsShown() then
                    for _, slotDef in ipairs(AD.SLOTS) do
                        local btn = slotButtons[slotDef.key]
                        if btn then RefreshSlotButton(btn, slotDef) end
                    end
                    RefreshGearList()
                end
            end)
        end
    end
end

local function CreateSlotButton(doll, slotDef)
    local btn = UI.CreateIconButton(doll.dollFrame, SLOT_SIZE)

    local empty = btn:CreateTexture(nil, "OVERLAY")
    empty:SetAllPoints(btn.icon)
    empty:SetTexture(0, 0, 0, 0.25)
    btn._empty = empty

    WireSlotTooltip(btn, slotDef)

    btn:SetScript("OnClick", function()
        EbonholdHub.ItemPicker.Show(function(entry)
            if entry then
                EL.SetSlot(slotDef.key, entry)
                RefreshAll()
            end
        end, slotDef)
    end)
    btn:SetScript("OnMouseUp", function(_, button)
        if button == "RightButton" then
            EL.SetSlot(slotDef.key, nil)
            RefreshAll()
        end
    end)

    EbonholdHub.AffixDoll.RegisterSlot(doll, slotDef.key, btn)
    return btn
end

local function BuildViewFrame(parent)
    local f = CreateFrame("Frame", nil, parent)
    SW.Fill(f, SC.mainBg)

    -- Toolbar: full-width, SC.sidebarBg + bottom separator
    local toolbar = CreateFrame("Frame", nil, f)
    toolbar:SetPoint("TOPLEFT",  f, "TOPLEFT",  0, 0)
    toolbar:SetPoint("TOPRIGHT", f, "TOPRIGHT", 0, 0)
    toolbar:SetHeight(HEADER_H)
    SW.Fill(toolbar, SC.sidebarBg)
    local toolbarSep = toolbar:CreateTexture(nil, "ARTWORK")
    toolbarSep:SetTexture(ST.FLAT)
    toolbarSep:SetVertexColor(unpack(SC.border))
    toolbarSep:SetHeight(1)
    toolbarSep:SetPoint("BOTTOMLEFT",  toolbar, "BOTTOMLEFT",  0, 0)
    toolbarSep:SetPoint("BOTTOMRIGHT", toolbar, "BOTTOMRIGHT", 0, 0)

    -- Row 1: GearSetStrip
    setStrip = EbonholdHub.GearSetStrip.Create(toolbar, {
        onChange = function() RefreshAll() end,
    })
    setStrip:SetPoint("TOPLEFT",  toolbar, "TOPLEFT",  HEADER_PAD,  -HEADER_PAD)
    setStrip:SetPoint("TOPRIGHT", toolbar, "TOPRIGHT", -HEADER_PAD, -HEADER_PAD)

    -- Row 2: action buttons
    headerActions = CreateFrame("Frame", nil, toolbar)
    headerActions:SetHeight(ACTION_H)
    headerActions:SetPoint("TOPLEFT",  setStrip, "BOTTOMLEFT",  0,           -4)
    headerActions:SetPoint("TOPRIGHT", toolbar,  "TOPRIGHT",   -HEADER_PAD,  0)

    local copyBtn = SW.CreateOutlineButton(headerActions, "Copy from character", 152)
    copyBtn:SetHeight(ACTION_H)
    copyBtn:SetPoint("LEFT", headerActions, "LEFT", 0, 0)
    copyBtn:SetScript("OnClick", function()
        EL.CopyFromPlayer()
        RefreshAll()
    end)

    local clearBtn = SW.CreateOutlineButton(headerActions, "Clear all", 80)
    clearBtn:SetHeight(ACTION_H)
    clearBtn:SetPoint("LEFT", copyBtn, "RIGHT", 6, 0)
    clearBtn:SetScript("OnClick", function()
        EL.ClearAll()
        RefreshAll()
    end)

    -- Body: below toolbar with content padding
    bodyFrame = CreateFrame("Frame", nil, f)
    bodyFrame:SetPoint("TOPLEFT",     toolbar, "BOTTOMLEFT",  SL.PAD,  -SL.PAD)
    bodyFrame:SetPoint("BOTTOMRIGHT", f,       "BOTTOMRIGHT", -SL.PAD,  SL.PAD)

    -- Left: doll panel
    leftPanel = CreateFrame("Frame", nil, bodyFrame)
    SW.Fill(leftPanel, SC.statCellBg)
    SW.ThinBorder(leftPanel, SC.border, 1)
    leftPanel:SetPoint("TOPLEFT",    bodyFrame, "TOPLEFT",    0, 0)
    leftPanel:SetPoint("BOTTOMLEFT", bodyFrame, "BOTTOMLEFT", 0, 0)
    leftPanel:SetWidth(DOLL_W)

    dollHolder = EbonholdHub.AffixDoll.Create(leftPanel, { slotSize = SLOT_SIZE, showModel = true })
    dollHolder:SetPoint("TOPLEFT",     leftPanel, "TOPLEFT",     8, -8)
    dollHolder:SetPoint("TOPRIGHT",    leftPanel, "TOPRIGHT",   -8, -8)
    dollHolder:SetPoint("BOTTOMLEFT",  leftPanel, "BOTTOMLEFT",  8,  8)
    dollHolder:SetPoint("BOTTOMRIGHT", leftPanel, "BOTTOMRIGHT", -8,  8)

    slotButtons = {}
    for _, slotDef in ipairs(AD.SLOTS) do
        slotButtons[slotDef.key] = CreateSlotButton(dollHolder, slotDef)
    end
    dollHolder:Layout()

    -- Right: gear list panel
    rightPanel = CreateFrame("Frame", nil, bodyFrame)
    SW.Fill(rightPanel, SC.statCellBg)
    SW.ThinBorder(rightPanel, SC.border, 1)
    rightPanel:SetPoint("TOPLEFT",     leftPanel,  "TOPRIGHT",    GAP, 0)
    rightPanel:SetPoint("BOTTOMRIGHT", bodyFrame,  "BOTTOMRIGHT",   0, 0)

    gearListScroll, gearListChild = SW.CreatePlainScroll(rightPanel)

    f._layoutV3 = true
    -- store RefreshAll for gear list row callbacks
    f._refreshAll = RefreshAll
    return f
end

local function ResetView()
    viewFrame = nil
    slotButtons = {}
    dollHolder = nil
    gearListScroll = nil
    gearListChild = nil
    headerActions = nil
    setStrip = nil
end

local function EnsureBuilt(container)
    if viewFrame and viewFrame._layoutV3 then return end
    ResetView()
    viewFrame = BuildViewFrame(container)
end

function EbonholdHub.GearView.Mount(container)
    EnsureBuilt(container)
    viewFrame:SetParent(container)
    viewFrame:ClearAllPoints()
    viewFrame:SetAllPoints(container)
    if setStrip then setStrip:Refresh() end
    RefreshAll()
    viewFrame:Show()
end

function EbonholdHub.GearView.Unmount()
    if viewFrame then viewFrame:Hide() end
    EbonholdHub.ItemPicker.Hide()
end

function EbonholdHub.GearView.Init()
end
