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

local GearItemLevelRuntime = {
    enabled = false,
    hooksReady = false,
}

local function isCharacterFrameShown()
    local characterFrame = _G.CharacterFrame
    return characterFrame and characterFrame.IsShown and characterFrame:IsShown()
end

local function ensureGearItemLevelFont()
    local existing = _G.VaultloomGearItemLevelFont
    if existing then
        return existing
    end

    local font = CreateFont("VaultloomGearItemLevelFont")
    font:SetFont(STANDARD_TEXT_FONT, 10, "OUTLINE")
    font:SetShadowOffset(1, -1)
    font:SetShadowColor(0, 0, 0, 0.95)
    return font
end

local function ensureGearItemLevelOverlay(slotButton)
    if not slotButton then
        return nil
    end

    local text = slotButton.VaultloomItemLevelText
    if text then
        return text
    end

    text = slotButton:CreateFontString(nil, "OVERLAY")
    text:SetFontObject(ensureGearItemLevelFont())
    text:SetJustifyH("CENTER")
    text:SetPoint("BOTTOM", slotButton, "BOTTOM", 0, 3)
    text:SetText("")
    text:Hide()

    slotButton.VaultloomItemLevelText = text
    return text
end

local function getGearItemLevelColor(slotID)
    local textStyle = ns.GetFeatureOptionValue and ns:GetFeatureOptionValue("gear_item_level", "text_style") or "white"
    if textStyle ~= "quality" then
        return 1, 1, 1
    end

    local quality = nil
    if type(GetInventoryItemQuality) == "function" then
        local okQuality, rawQuality = pcall(GetInventoryItemQuality, "player", slotID)
        if okQuality then
            quality = tonumber(rawQuality)
        end
    end

    local color = quality ~= nil and ITEM_QUALITY_COLORS and ITEM_QUALITY_COLORS[quality] or nil
    if color then
        return color.r, color.g, color.b
    end

    return 1, 1, 1
end

local function getEquippedItemLevel(slotID)
    slotID = tonumber(slotID)
    if not slotID or slotID < 1 then
        return nil
    end

    local itemLink = type(GetInventoryItemLink) == "function" and GetInventoryItemLink("player", slotID) or nil
    if not itemLink then
        return nil
    end

    local itemLevel = nil
    if type(GetDetailedItemLevelInfo) == "function" then
        local okLevel, resolvedLevel = pcall(GetDetailedItemLevelInfo, itemLink)
        if okLevel then
            itemLevel = tonumber(resolvedLevel)
        end
    end

    if not itemLevel and C_Item and ItemLocation and type(ItemLocation.CreateFromEquipmentSlot) == "function" then
        local itemLocation = ItemLocation:CreateFromEquipmentSlot(slotID)
        if itemLocation and C_Item.DoesItemExist and C_Item.DoesItemExist(itemLocation) and type(C_Item.GetCurrentItemLevel) == "function" then
            local okCurrent, currentLevel = pcall(C_Item.GetCurrentItemLevel, itemLocation)
            if okCurrent then
                itemLevel = tonumber(currentLevel)
            end
        end
    end

    return itemLevel and math.floor(itemLevel + 0.5) or nil
end

function GearItemLevelRuntime:RefreshSlot(slotButton)
    if not slotButton then
        return
    end

    if self.enabled ~= true then
        local text = slotButton.VaultloomItemLevelText
        if text then
            text:Hide()
        end
        return
    end

    if not isCharacterFrameShown() then
        local text = slotButton.VaultloomItemLevelText
        if text then
            text:Hide()
        end
        return
    end

    local text = ensureGearItemLevelOverlay(slotButton)
    if not text then
        return
    end

    if self.enabled ~= true then
        text:Hide()
        return
    end

    local slotID = tonumber(slotButton:GetID())
    local itemLevel = getEquippedItemLevel(slotID)
    if not itemLevel then
        text:Hide()
        return
    end

    local r, g, b = getGearItemLevelColor(slotID)
    text:SetText(itemLevel)
    text:SetTextColor(r, g, b, 1)
    text:Show()
end

function GearItemLevelRuntime:RefreshAll()
    if self.enabled ~= true or not isCharacterFrameShown() then
        return
    end

    for _, slotName in ipairs(ns:GetCharacterGearSlotNames()) do
        self:RefreshSlot(ns:GetCharacterGearSlotButton(slotName))
    end
end

function GearItemLevelRuntime:HideAll()
    for _, slotName in ipairs(ns:GetCharacterGearSlotNames()) do
        local slotButton = ns:GetCharacterGearSlotButton(slotName)
        local text = slotButton and slotButton.VaultloomItemLevelText or nil
        if text then
            text:Hide()
        end
    end
end

function GearItemLevelRuntime:EnsureHooks()
    if self.hooksReady then
        return
    end

    local paperDollReady = type(PaperDollItemSlotButton_Update) == "function"
    local characterFrame = _G.CharacterFrame
    if not paperDollReady and not characterFrame then
        return
    end

    self.hooksReady = true

    if type(hooksecurefunc) == "function" and paperDollReady then
        hooksecurefunc("PaperDollItemSlotButton_Update", function(button)
            if button and button.GetName and tostring(button:GetName() or ""):match("^Character") then
                GearItemLevelRuntime:RefreshSlot(button)
            end
        end)
    end

    if characterFrame and characterFrame.HookScript then
        characterFrame:HookScript("OnShow", function()
            GearItemLevelRuntime:RefreshAll()
        end)
    end
end

function GearItemLevelRuntime:SetEnabled(enabled)
    enabled = enabled == true
    self.enabled = enabled

    if not self.eventFrame then
        self.eventFrame = CreateFrame("Frame")
        self.eventFrame:SetScript("OnEvent", function(_, event, ...)
            if event == "ADDON_LOADED" then
                local loadedName = ...
                if loadedName == "Blizzard_CharacterUI" then
                    GearItemLevelRuntime:EnsureHooks()
                    GearItemLevelRuntime:RefreshAll()
                end
                return
            end

            if event == "UNIT_INVENTORY_CHANGED" then
                local unit = ...
                if unit ~= "player" then
                    return
                end
            end

            GearItemLevelRuntime:RefreshAll()
        end)
    end

    self.eventFrame:UnregisterAllEvents()

    if not enabled then
        self:HideAll()
        return
    end

    self:EnsureHooks()
    self.eventFrame:RegisterEvent("ADDON_LOADED")
    self.eventFrame:RegisterEvent("PLAYER_ENTERING_WORLD")
    self.eventFrame:RegisterEvent("PLAYER_EQUIPMENT_CHANGED")
    self.eventFrame:RegisterEvent("UNIT_INVENTORY_CHANGED")
    self.eventFrame:RegisterEvent("BAG_UPDATE_DELAYED")
    self:RefreshAll()
end

ns:RegisterFeatureDefinition("gear_item_level", {
    id = "gear_item_level",
    order = 20,
    category = "character",
    title = function() return L.FEATURE_GEAR_ITEM_LEVEL_TITLE or "Gear Item Level" end,
    description = function() return L.FEATURE_GEAR_ITEM_LEVEL_DESCRIPTION or "Shows item level directly on your gear slots." end,
    note = function() return L.FEATURE_GEAR_ITEM_LEVEL_NOTE or "Only in the character window." end,
    previewLabel = function() return L.FEATURE_GEAR_ITEM_LEVEL_PREVIEW_LABEL or "Character Overlay" end,
    previewNote = function() return L.FEATURE_GEAR_ITEM_LEVEL_PREVIEW_NOTE or "Compact item level numbers on gear icons with matching item-quality colors." end,
    optionToggle = {
        key = "text_style",
        label = function() return L.FEATURE_GEAR_ITEM_LEVEL_STYLE_LABEL or "Text Style" end,
        values = { "white", "quality" },
        defaultValue = "white",
        valueLabels = {
            white = function() return L.FEATURE_GEAR_ITEM_LEVEL_STYLE_WHITE or "White" end,
            quality = function() return L.FEATURE_GEAR_ITEM_LEVEL_STYLE_COLORED or "Colored" end,
        },
    },
    requiresReload = false,
    apply = function(isEnabled)
        GearItemLevelRuntime:SetEnabled(isEnabled == true)
    end,
    onOptionChanged = function()
        GearItemLevelRuntime:RefreshAll()
    end,
})
