local _, ns = ...
local L = ns.L or {}

local UIData = ns.UIData or {}
local PREMIUM = UIData.PREMIUM or {}
local THEME = UIData.THEME or {}
local MID_UPGRADE_CRESTS = type(ns.MID_UPGRADE_CRESTS) == "table" and ns.MID_UPGRADE_CRESTS or {}
local MID_RESOURCE_ENTRIES = type(ns.MID_RESOURCE_ENTRIES) == "table" and ns.MID_RESOURCE_ENTRIES or {}

local UIUtilityView = {}
ns.UIUtilityView = UIUtilityView

local BACKDROP_TEMPLATE = BackdropTemplateMixin and "BackdropTemplate" or nil
local characterFrameOriginalStrata
local characterFrameRestoreHooked = false

local function restoreCharacterFrameStacking(frame)
    if characterFrameOriginalStrata and type(frame) == "table" and type(frame.SetFrameStrata) == "function" then
        pcall(frame.SetFrameStrata, frame, characterFrameOriginalStrata)
    end

    characterFrameOriginalStrata = nil
end

local function bringCharacterFrameToFront()
    local frame = _G and _G.CharacterFrame or nil
    if type(frame) ~= "table" then
        return
    end

    if type(frame.GetFrameStrata) == "function" and type(frame.SetFrameStrata) == "function" and not characterFrameOriginalStrata then
        local ok, strata = pcall(frame.GetFrameStrata, frame)
        if ok and type(strata) == "string" and strata ~= "DIALOG" then
            characterFrameOriginalStrata = strata
        end
    end

    if not characterFrameRestoreHooked and type(frame.HookScript) == "function" then
        characterFrameRestoreHooked = true
        frame:HookScript("OnHide", restoreCharacterFrameStacking)
    end

    if type(frame.SetFrameStrata) == "function" then
        pcall(frame.SetFrameStrata, frame, "DIALOG")
    end
    if type(frame.Raise) == "function" then
        pcall(frame.Raise, frame)
    end
end

local function openCurrencyTab()
    if C_AddOns and type(C_AddOns.LoadAddOn) == "function" then
        pcall(C_AddOns.LoadAddOn, "Blizzard_TokenUI")
    elseif type(LoadAddOn) == "function" then
        pcall(LoadAddOn, "Blizzard_TokenUI")
    end

    if type(TokenFrame_LoadUI) == "function" then
        pcall(TokenFrame_LoadUI)
    end

    local characterFrame = _G and _G.CharacterFrame or nil
    local tokenFrame = _G and _G.TokenFrame or nil
    if characterFrame and tokenFrame and type(characterFrame.IsShown) == "function" and type(tokenFrame.IsShown) == "function" and characterFrame:IsShown() and tokenFrame:IsShown() then
        bringCharacterFrameToFront()
        return true
    end

    if type(ToggleCharacter) == "function" then
        local ok = pcall(ToggleCharacter, "TokenFrame")
        if ok then
            bringCharacterFrameToFront()
            return true
        end
    end

    if type(CharacterFrame_ShowSubFrame) == "function" and characterFrame then
        pcall(CharacterFrame_ShowSubFrame, "TokenFrame")
        if type(ShowUIPanel) == "function" then
            pcall(ShowUIPanel, characterFrame)
        elseif type(characterFrame.Show) == "function" then
            pcall(characterFrame.Show, characterFrame)
        end
        bringCharacterFrameToFront()
        return true
    end

    return false
end

local function styleHeader(header)
    if not header then
        return
    end

    if header.line then
        header.line:SetAlpha(0)
    end
    if header.label then
        local color = THEME.parchment or { 0.93, 0.89, 0.77 }
        header.label:SetTextColor(color[1], color[2], color[3], 0.92)
    end
    if header.SetBackdropBorderColor and THEME.goldDim then
        header:SetBackdropBorderColor(THEME.goldDim[1], THEME.goldDim[2], THEME.goldDim[3], 0.32)
    end
end

local function getCurrencyRecord(currencyID)
    if not C_CurrencyInfo or not C_CurrencyInfo.GetCurrencyInfo then
        return nil
    end

    local info = C_CurrencyInfo.GetCurrencyInfo(currencyID)
    if not info then
        return nil
    end

    return {
        name = info.name or ("Currency " .. tostring(currencyID)),
        icon = info.iconFileID,
        quantity = tonumber(info.quantity) or 0,
    }
end

local function getItemRecord(itemID)
    local count = C_Item and C_Item.GetItemCount and C_Item.GetItemCount(itemID, true, false, true, true) or 0
    local name = C_Item and C_Item.GetItemNameByID and C_Item.GetItemNameByID(itemID) or nil
    local icon = C_Item and C_Item.GetItemIconByID and C_Item.GetItemIconByID(itemID) or nil

    return {
        name = name or ("Item " .. tostring(itemID)),
        icon = icon,
        quantity = tonumber(count) or 0,
    }
end

local function getUtilityEntryKey(entry)
    if type(entry) ~= "table" then
        return nil
    end

    if entry.currencyID then
        return "currency:" .. tostring(entry.currencyID)
    end

    if entry.itemID then
        return "item:" .. tostring(entry.itemID)
    end

    return nil
end

local function showCurrencyOrItemTooltip(owner, currencyID, itemID)
    if not owner then
        return
    end

    GameTooltip:SetOwner(owner, "ANCHOR_CURSOR_RIGHT")
    if currencyID then
        GameTooltip:SetCurrencyByID(currencyID)
    elseif itemID then
        GameTooltip:SetItemByID(itemID)
    end

    if type(owner.resourceHintText) == "string" and owner.resourceHintText ~= "" then
        GameTooltip:AddLine(" ")
        GameTooltip:AddLine(owner.resourceHintText, 0.82, 0.78, 0.66, true)
    end

    GameTooltip:Show()
end

local function createUpgradeButton(parent, helpers)
    local createLabel = helpers.createLabel
    local setTextureColor = helpers.setTextureColor

    local button = CreateFrame("Frame", nil, parent, BACKDROP_TEMPLATE)
    button:SetSize(40, 52)

    if button.SetBackdrop then
        button:SetBackdrop({
            bgFile = "Interface\\Buttons\\WHITE8X8",
            edgeFile = "Interface\\Buttons\\WHITE8X8",
            tile = false,
            edgeSize = 1,
            insets = { left = 1, right = 1, top = 1, bottom = 1 },
        })
        button:SetBackdropColor(THEME.metalInset[1], THEME.metalInset[2], THEME.metalInset[3], 0)
        button:SetBackdropBorderColor(THEME.goldDim[1], THEME.goldDim[2], THEME.goldDim[3], 0)
    end

    button.bg = button:CreateTexture(nil, "BACKGROUND")
    button.bg:SetAllPoints()
    button.bg:SetTexture(PREMIUM.cardInset)
    setTextureColor(button.bg, { 1, 1, 1 }, 0)

    button.overlay = button:CreateTexture(nil, "BACKGROUND", nil, 1)
    button.overlay:SetAllPoints()
    button.overlay:SetTexture(PREMIUM.insetOverlay)
    setTextureColor(button.overlay, { 1, 1, 1 }, 0)

    button.shade = button:CreateTexture(nil, "BACKGROUND", nil, 2)
    button.shade:SetPoint("TOPLEFT", 1, -1)
    button.shade:SetPoint("BOTTOMRIGHT", -1, 1)
    button.shade:SetTexture("Interface\\Buttons\\WHITE8X8")
    button.shade:SetColorTexture(THEME.shadow[1], THEME.shadow[2], THEME.shadow[3], 0.01)

    button.icon = button:CreateTexture(nil, "ARTWORK")
    button.icon:SetSize(31, 31)
    button.icon:SetPoint("TOP", 0, -7)

    button.iconBorderTop = button:CreateTexture(nil, "OVERLAY", nil, 1)
    button.iconBorderTop:SetHeight(1)
    button.iconBorderTop:SetPoint("TOPLEFT", button.icon, "TOPLEFT", 0, 0)
    button.iconBorderTop:SetPoint("TOPRIGHT", button.icon, "TOPRIGHT", 0, 0)
    button.iconBorderTop:SetTexture("Interface\\Buttons\\WHITE8X8")

    button.iconBorderBottom = button:CreateTexture(nil, "OVERLAY", nil, 1)
    button.iconBorderBottom:SetHeight(1)
    button.iconBorderBottom:SetPoint("BOTTOMLEFT", button.icon, "BOTTOMLEFT", 0, 0)
    button.iconBorderBottom:SetPoint("BOTTOMRIGHT", button.icon, "BOTTOMRIGHT", 0, 0)
    button.iconBorderBottom:SetTexture("Interface\\Buttons\\WHITE8X8")

    button.iconBorderLeft = button:CreateTexture(nil, "OVERLAY", nil, 1)
    button.iconBorderLeft:SetWidth(1)
    button.iconBorderLeft:SetPoint("TOPLEFT", button.icon, "TOPLEFT", 0, 0)
    button.iconBorderLeft:SetPoint("BOTTOMLEFT", button.icon, "BOTTOMLEFT", 0, 0)
    button.iconBorderLeft:SetTexture("Interface\\Buttons\\WHITE8X8")

    button.iconBorderRight = button:CreateTexture(nil, "OVERLAY", nil, 1)
    button.iconBorderRight:SetWidth(1)
    button.iconBorderRight:SetPoint("TOPRIGHT", button.icon, "TOPRIGHT", 0, 0)
    button.iconBorderRight:SetPoint("BOTTOMRIGHT", button.icon, "BOTTOMRIGHT", 0, 0)
    button.iconBorderRight:SetTexture("Interface\\Buttons\\WHITE8X8")

    button.count = createLabel(button, "GameFontHighlightSmall", "CENTER")
    button.count:SetPoint("TOP", button.icon, "BOTTOM", 0, -5)
    button.count:SetWidth(42)
    button.count:SetText("0")

    button:SetScript("OnEnter", function(self)
        if self.currencyID or self.itemID then
            showCurrencyOrItemTooltip(self, self.currencyID, self.itemID)
        end
    end)
    button:SetScript("OnLeave", function()
        GameTooltip:Hide()
    end)

    return button
end

local function createResourceRow(parent, helpers)
    local createLabel = helpers.createLabel
    local setTextureColor = helpers.setTextureColor

    local row = CreateFrame("Button", nil, parent, BACKDROP_TEMPLATE)
    row:SetHeight(25)
    row:RegisterForClicks("LeftButtonUp", "RightButtonUp")

    if row.SetBackdrop then
        row:SetBackdrop({
            bgFile = "Interface\\Buttons\\WHITE8X8",
            edgeFile = "Interface\\Buttons\\WHITE8X8",
            tile = false,
            edgeSize = 1,
            insets = { left = 1, right = 1, top = 1, bottom = 1 },
        })
        row:SetBackdropColor(THEME.metalDeep[1], THEME.metalDeep[2], THEME.metalDeep[3], 0.04)
        row:SetBackdropBorderColor(THEME.goldDim[1], THEME.goldDim[2], THEME.goldDim[3], 0.24)
    end

    row.bg = row:CreateTexture(nil, "BACKGROUND")
    row.bg:SetAllPoints()
    row.bg:SetTexture(PREMIUM.row)
    setTextureColor(row.bg, { 1, 1, 1 }, 0.94)

    row.overlay = row:CreateTexture(nil, "BACKGROUND", nil, 1)
    row.overlay:SetAllPoints()
    row.overlay:SetTexture(PREMIUM.insetOverlay)
    setTextureColor(row.overlay, { 1, 1, 1 }, 0.05)

    row.shade = row:CreateTexture(nil, "BACKGROUND", nil, 2)
    row.shade:SetPoint("TOPLEFT", 1, -1)
    row.shade:SetPoint("BOTTOMRIGHT", -1, 1)
    row.shade:SetTexture("Interface\\Buttons\\WHITE8X8")
    row.shade:SetColorTexture(THEME.shadow[1], THEME.shadow[2], THEME.shadow[3], 0.01)

    row.hover = row:CreateTexture(nil, "BACKGROUND", nil, 3)
    row.hover:SetAllPoints()
    row.hover:SetTexture("Interface\\Buttons\\WHITE8X8")
    row.hover:SetColorTexture(THEME.gold[1], THEME.gold[2], THEME.gold[3], 0.08)
    row.hover:SetAlpha(0)

    row.name = createLabel(row, "GameFontHighlightSmall", "LEFT")
    row.name:SetPoint("LEFT", 9, 0)
    row.name:SetPoint("RIGHT", -58, 0)
    if row.name.SetWordWrap then
        row.name:SetWordWrap(false)
    end

    row.value = createLabel(row, "GameFontNormalSmall", "RIGHT")
    row.value:SetPoint("RIGHT", -31, 0)
    row.value:SetWidth(72)

    row.icon = row:CreateTexture(nil, "ARTWORK")
    row.icon:SetSize(19, 19)
    row.icon:SetPoint("RIGHT", -8, 0)
    row.resourceHintText = L.RESOURCE_HIDE_HINT or "Left-click hides this resource only in Vaultloom. Right-click opens WoW's currency tab."

    row:SetScript("OnEnter", function(self)
        if self.currencyID or self.itemID then
            self.hover:SetAlpha(1)
            showCurrencyOrItemTooltip(self, self.currencyID, self.itemID)
        end
    end)
    row:SetScript("OnLeave", function(self)
        self.hover:SetAlpha(0)
        GameTooltip:Hide()
    end)
    row:SetScript("OnClick", function(self, buttonName)
        if buttonName == "RightButton" then
            GameTooltip:Hide()
            openCurrencyTab()
            return
        end

        if buttonName ~= "LeftButton" or not self.entryKey or not ns.SetUtilityResourceHidden then
            return
        end

        GameTooltip:Hide()
        ns:SetUtilityResourceHidden(self.entryKey, true)
    end)

    return row
end

local function ensureResourceRows(ui, count, helpers)
    while #ui.frame.resourceRows < count do
        local row = createResourceRow(ui.frame.resourceScrollChild, helpers)
        local index = #ui.frame.resourceRows + 1
        row:SetPoint("TOPLEFT", 0, -((index - 1) * 29))
        row:SetPoint("TOPRIGHT", 0, -((index - 1) * 29))
        ui.frame.resourceRows[index] = row
    end
end

local function refreshUtility(ui, character, helpers)
    if not ui.frame or not ui.frame.utility then
        return
    end

    local setMiniActionButtonActive = helpers.setMiniActionButtonActive
    local isCurrentCharacter = character and ns:IsCurrentCharacterKey(character.key)
    local utilityState = ns.GetCharacterUtilityState and ns:GetCharacterUtilityState(character) or nil

    if ui.frame.resourceInfo then
        ui.frame.resourceInfo:SetText("")
        ui.frame.resourceInfo:Hide()
    end

    local hiddenResourceCount = ns.GetHiddenUtilityResourceCount and ns:GetHiddenUtilityResourceCount() or 0
    if ui.frame.resourceRestoreButton then
        local restoreLabel = hiddenResourceCount > 0
            and string.format(L.RESOURCE_SHOW_ALL_COUNT or "Show all (%d)", hiddenResourceCount)
            or (L.RESOURCE_SHOW_ALL or "Show all")
        ui.frame.resourceRestoreButton.hiddenCount = hiddenResourceCount
        ui.frame.resourceRestoreButton.label:SetText(restoreLabel)
        setMiniActionButtonActive(ui.frame.resourceRestoreButton, hiddenResourceCount > 0)
    end

    for index, button in ipairs(ui.frame.upgradeButtons or {}) do
        local currencyID = MID_UPGRADE_CRESTS[index]
        local storedRecord = utilityState and utilityState.upgrades and utilityState.upgrades[tostring(currencyID)] or nil
        local record = isCurrentCharacter and getCurrencyRecord(currencyID) or storedRecord
        local previewRecord = not isCurrentCharacter and getCurrencyRecord(currencyID) or nil
        local borderColor = nil
        button.currencyID = currencyID
        button.itemID = nil

        if ITEM_QUALITY_COLORS then
            if currencyID == 3383 then
                borderColor = ITEM_QUALITY_COLORS[3]
            elseif currencyID == 3347 or currencyID == 3345 or currencyID == 3343 or currencyID == 3341 then
                borderColor = ITEM_QUALITY_COLORS[4]
            end
        end

        local borderR = borderColor and borderColor.r or THEME.goldDim[1]
        local borderG = borderColor and borderColor.g or THEME.goldDim[2]
        local borderB = borderColor and borderColor.b or THEME.goldDim[3]
        local borderA = 0.36

        if (record and record.icon) or (previewRecord and previewRecord.icon) then
            button.icon:SetTexture((record and record.icon) or (previewRecord and previewRecord.icon))
            button.icon:SetDesaturated(not record)
            if record then
                button.count:SetText(tostring(record.quantity or 0))
                button.count:SetTextColor(0.95, 0.92, 0.82)
                button:SetAlpha(1)
                borderA = 0.92
            else
                button.count:SetText(L.UTILITY_VALUE_UNKNOWN or "--")
                button.count:SetTextColor(0.55, 0.58, 0.64)
                button:SetAlpha(isCurrentCharacter and 0.55 or 0.42)
                borderA = 0.42
            end
        else
            button.icon:SetTexture("Interface\\ICONS\\INV_Misc_QuestionMark")
            button.icon:SetDesaturated(true)
            button.count:SetText(L.UTILITY_VALUE_UNKNOWN or "--")
            button.count:SetTextColor(0.55, 0.58, 0.64)
            button:SetAlpha(isCurrentCharacter and 0.55 or 0.42)
        end

        button.iconBorderTop:SetColorTexture(borderR, borderG, borderB, borderA)
        button.iconBorderBottom:SetColorTexture(borderR, borderG, borderB, borderA)
        button.iconBorderLeft:SetColorTexture(borderR, borderG, borderB, borderA)
        button.iconBorderRight:SetColorTexture(borderR, borderG, borderB, borderA)
    end

    ensureResourceRows(ui, #MID_RESOURCE_ENTRIES, helpers)

    local visibleResourceEntries = {}
    for _, entry in ipairs(MID_RESOURCE_ENTRIES) do
        local entryKey = getUtilityEntryKey(entry)
        if not (entryKey and ns.IsUtilityResourceHidden and ns:IsUtilityResourceHidden(entryKey)) then
            visibleResourceEntries[#visibleResourceEntries + 1] = entry
        end
    end

    local rowCount = 0
    for index, row in ipairs(ui.frame.resourceRows or {}) do
        local entry = visibleResourceEntries[index]
        if not entry then
            row.entryKey = nil
            row.currencyID = nil
            row.itemID = nil
            row:Hide()
        else
            local entryKey = getUtilityEntryKey(entry)
            local storedRecord = entryKey and utilityState and utilityState.resources and utilityState.resources[entryKey] or nil
            local record
            local previewRecord
            if isCurrentCharacter then
                if entry.currencyID then
                    record = getCurrencyRecord(entry.currencyID)
                elseif entry.itemID then
                    record = getItemRecord(entry.itemID)
                end
            else
                record = storedRecord
                if entry.currencyID then
                    previewRecord = getCurrencyRecord(entry.currencyID)
                elseif entry.itemID then
                    previewRecord = getItemRecord(entry.itemID)
                end
            end

            rowCount = rowCount + 1
            row:Show()
            row.entryKey = entryKey
            row.currencyID = entry.currencyID
            row.itemID = entry.itemID
            row.name:SetText((record and record.name) or (previewRecord and previewRecord.name) or "...")
            row.value:SetText(record and tostring(record.quantity or 0) or (L.UTILITY_VALUE_UNKNOWN or "--"))
            row.icon:SetTexture((record and record.icon) or (previewRecord and previewRecord.icon) or "Interface\\ICONS\\INV_Misc_QuestionMark")
            row.icon:SetDesaturated(not record)

            if record then
                row.name:SetTextColor(0.88, 0.88, 0.84)
                row.value:SetTextColor(0.94, 0.92, 0.82)
                row:SetAlpha(1)
            else
                row.name:SetTextColor(0.60, 0.62, 0.68)
                row.value:SetTextColor(0.60, 0.62, 0.68)
                row:SetAlpha(isCurrentCharacter and 0.55 or 0.44)
            end
        end
    end

    local totalHeight = math.max(10, (rowCount * 29) - 4)
    ui.frame.resourceScrollChild:SetSize(216, totalHeight)
end

UIUtilityView.CreateUpgradeButton = createUpgradeButton
UIUtilityView.CreateResourceRow = createResourceRow
UIUtilityView.EnsureResourceRows = ensureResourceRows
UIUtilityView.Refresh = refreshUtility
UIUtilityView.StyleHeader = styleHeader
