local _, addon = ...
local HLY = addon.HLY
local P = addon.P

local _G = _G
local format = format
local ipairs = ipairs
local next = next
local pairs = pairs
local strlower = strlower
local strmatch = strmatch
local strtrim = strtrim

local C_TooltipInfo = C_TooltipInfo
local ITEM_CLASS_RECIPE = (Enum and Enum.ItemClass and Enum.ItemClass.Recipe) or LE_ITEM_CLASS_RECIPE

local UPGRADE_PATTERN = "(%d+/%d+)"
local PARENS_UPGRADE_PATTERN = "^%s*%(%d+/%d+%)%s*$"
local UPGRADE_KEYWORDS = {
    "upgrade",
    "aufwertung",
}

local function NormalizeUpgradeLine(text)
    if not text or text == "" then
        return nil
    end

    local cleaned = strtrim(text)
    local afterColon = strmatch(cleaned, "^.-:%s*(.+)$")
    if afterColon and afterColon ~= "" then
        cleaned = strtrim(afterColon)
    end

    local label, ratio = strmatch(cleaned, "^(.-)%s*(%d+/%d+)%s*$")
    if ratio then
        label = strtrim(label or "")
        if label ~= "" then
            local initial = label:sub(1, 1)
            local lower = strlower(label)
            local trackKey

            if lower:find("adventurer") or lower:find("abenteurer") then
                trackKey = "adventurer"
            elseif lower:find("veteran") then
                trackKey = "veteran"
            elseif lower:find("champion") then
                trackKey = "champion"
            elseif lower:find("hero") or lower:find("held") then
                trackKey = "hero"
            elseif lower:find("myth") or lower:find("mythisch") then
                trackKey = "mythic"
            end

            return format("%s %s", initial, ratio), trackKey, lower, ratio
        end

        return ratio, nil, cleaned:lower(), ratio
    end

    return cleaned, nil, cleaned:lower(), nil
end

local function ExtractUpgradeLine(tooltipData)
    if not tooltipData or not tooltipData.lines then
        return nil
    end

    for _, line in ipairs(tooltipData.lines) do
        local text = line.leftText
        if text and strmatch(text, UPGRADE_PATTERN) and not strmatch(text, PARENS_UPGRADE_PATTERN) then
            if not strmatch(text, "%(%%d+/%%d+%)") then
                local normalized, trackKey, lower, ratio = NormalizeUpgradeLine(text)
                if trackKey then
                    return normalized, trackKey, ratio
                end

                for _, keyword in ipairs(UPGRADE_KEYWORDS) do
                    if lower:find(keyword) then
                        return normalized, trackKey, ratio
                    end
                end
            end
        end
    end

    return nil
end

function HLY:GetUpgradeLineForBagSlot(bag, slot)
    if not C_TooltipInfo or not C_TooltipInfo.GetBagItem then
        return nil
    end

    return ExtractUpgradeLine(C_TooltipInfo.GetBagItem(bag, slot))
end

function HLY:GetUpgradeLineForInventorySlot(unit, slotID)
    if not C_TooltipInfo or not C_TooltipInfo.GetInventoryItem then
        return nil
    end

    return ExtractUpgradeLine(C_TooltipInfo.GetInventoryItem(unit, slotID))
end

function HLY:ApplyTextStyle(text)
    local db = self.db.bagText
    self:ApplyFont(text, db.font, db.fontSize, "SHADOWOUTLINE")
    self:SetPoint(text, db.anchor, db.xOffset, db.yOffset)
end

function HLY:ApplyCharacterTextStyle(text)
    local db = self.db.characterText
    self:ApplyFont(text, db.font, db.fontSize, "SHADOWOUTLINE")
    self:SetPoint(text, db.anchor, db.xOffset, db.yOffset)
end

function HLY:ApplyInspectTextStyle(text)
    local db = self.db.characterText
    self:ApplyFont(text, db.font, db.fontSize, "SHADOWOUTLINE")
    self:SetPoint(text, db.anchor, db.xOffset, db.yOffset)
end

function HLY:UpdateSlotUpgradeText(slot, bagID, slotID)
    if not slot then
        return
    end

    if not slot.hlyUpgradeText then
        slot.hlyUpgradeText = slot:CreateFontString(nil, "OVERLAY")
        self:ApplyTextStyle(slot.hlyUpgradeText)
    end

    if not self.db.enabled or not self.db.bagText.enabled then
        slot.hlyUpgradeText:SetText("")
        slot.hlyUpgradeText:Hide()
        return
    end

    self:ApplyTextStyle(slot.hlyUpgradeText)

    local itemLink = slot.itemLink or self:GetBagItemLink(bagID, slotID)
    if not itemLink then
        slot.hlyUpgradeText:SetText("")
        slot.hlyUpgradeText:Hide()
        return
    end
    if ITEM_CLASS_RECIPE and slot.itemClassID == ITEM_CLASS_RECIPE then
        slot.hlyUpgradeText:SetText("")
        slot.hlyUpgradeText:Hide()
        return
    end

    self.upgradeCache = self.upgradeCache or {}
    local cacheKey = self:GetBagCacheKey(bagID, slotID)
    local cached = self.upgradeCache[cacheKey]

    local upgradeLine, trackKey, ratio
    if cached and cached.itemLink == itemLink then
        upgradeLine = cached.upgradeLine
        trackKey = cached.trackKey
        ratio = cached.ratio
    else
        upgradeLine, trackKey, ratio = self:GetUpgradeLineForBagSlot(bagID, slotID)
        self.upgradeCache[cacheKey] = {
            itemLink = itemLink,
            upgradeLine = upgradeLine,
            trackKey = trackKey,
            ratio = ratio,
        }
    end

    if upgradeLine and upgradeLine ~= "" then
        slot.hlyUpgradeText:SetText(self.db.bagText.showInitial == false and ratio and ratio or upgradeLine)
        slot.hlyUpgradeText:Show()

        local defaultColors = P.hlyqol.bagText.colors
        local color = trackKey and self.db.bagText.colors and self.db.bagText.colors[trackKey] or nil
        if trackKey and (not color or color.r == nil) then
            color = defaultColors[trackKey]
        end

        if color then
            slot.hlyUpgradeText:SetTextColor(color.r, color.g, color.b)
        else
            slot.hlyUpgradeText:SetTextColor(1, 1, 1)
        end
    else
        slot.hlyUpgradeText:SetText("")
        slot.hlyUpgradeText:Hide()
    end
end

function HLY:UpdateCharacterSlotUpgradeText(slot)
    if not slot then
        return
    end

    if not slot.hlyUpgradeTextCharacter then
        slot.hlyUpgradeTextCharacter = slot:CreateFontString(nil, "OVERLAY")
        self:ApplyCharacterTextStyle(slot.hlyUpgradeTextCharacter)
    end

    if not self.db.enabled or not self.db.characterText.enabled then
        slot.hlyUpgradeTextCharacter:SetText("")
        slot.hlyUpgradeTextCharacter:Hide()
        return
    end

    self:ApplyCharacterTextStyle(slot.hlyUpgradeTextCharacter)

    local slotID = slot:GetID()
    if not slotID then
        slot.hlyUpgradeTextCharacter:SetText("")
        slot.hlyUpgradeTextCharacter:Hide()
        return
    end

    local upgradeLine, trackKey, ratio = self:GetUpgradeLineForInventorySlot("player", slotID)
    if upgradeLine and upgradeLine ~= "" then
        slot.hlyUpgradeTextCharacter:SetText(self.db.characterText.showInitial == false and ratio and ratio or upgradeLine)
        slot.hlyUpgradeTextCharacter:Show()

        local defaultColors = P.hlyqol.bagText.colors
        local color = trackKey and self.db.bagText.colors and self.db.bagText.colors[trackKey] or nil
        if trackKey and (not color or color.r == nil) then
            color = defaultColors[trackKey]
        end

        if color then
            slot.hlyUpgradeTextCharacter:SetTextColor(color.r, color.g, color.b)
        else
            slot.hlyUpgradeTextCharacter:SetTextColor(1, 1, 1)
        end
    else
        slot.hlyUpgradeTextCharacter:SetText("")
        slot.hlyUpgradeTextCharacter:Hide()
    end
end

function HLY:UpdateInspectSlotUpgradeText(slot)
    if not slot then
        return
    end

    if not slot.hlyUpgradeTextInspect then
        slot.hlyUpgradeTextInspect = slot:CreateFontString(nil, "OVERLAY")
        self:ApplyInspectTextStyle(slot.hlyUpgradeTextInspect)
    end

    if not self.db.enabled or not self.db.characterText.enabled then
        slot.hlyUpgradeTextInspect:SetText("")
        slot.hlyUpgradeTextInspect:Hide()
        return
    end

    self:ApplyInspectTextStyle(slot.hlyUpgradeTextInspect)

    local inspectFrame = _G.InspectFrame
    if not inspectFrame or not inspectFrame.unit then
        slot.hlyUpgradeTextInspect:SetText("")
        slot.hlyUpgradeTextInspect:Hide()
        return
    end

    local slotID = slot:GetID()
    if not slotID then
        slot.hlyUpgradeTextInspect:SetText("")
        slot.hlyUpgradeTextInspect:Hide()
        return
    end

    local upgradeLine, trackKey, ratio = self:GetUpgradeLineForInventorySlot(inspectFrame.unit, slotID)
    if upgradeLine and upgradeLine ~= "" then
        slot.hlyUpgradeTextInspect:SetText(self.db.characterText.showInitial == false and ratio and ratio or upgradeLine)
        slot.hlyUpgradeTextInspect:Show()

        local defaultColors = P.hlyqol.bagText.colors
        local color = trackKey and self.db.bagText.colors and self.db.bagText.colors[trackKey] or nil
        if trackKey and (not color or color.r == nil) then
            color = defaultColors[trackKey]
        end

        if color then
            slot.hlyUpgradeTextInspect:SetTextColor(color.r, color.g, color.b)
        else
            slot.hlyUpgradeTextInspect:SetTextColor(1, 1, 1)
        end
    else
        slot.hlyUpgradeTextInspect:SetText("")
        slot.hlyUpgradeTextInspect:Hide()
    end
end

function HLY:RefreshAllSlots()
    self:ForEachBagSlot(function(slot, bagID, slotID)
        self:UpdateSlotUpgradeText(slot, bagID, slotID)
    end)
end

function HLY:RefreshCharacterSlots()
    if not _G.PaperDollItemsFrame then
        return
    end

    for _, slot in next, { _G.PaperDollItemsFrame:GetChildren() } do
        if slot and slot.GetID then
            self:UpdateCharacterSlotUpgradeText(slot)
        end
    end
end

function HLY:RefreshInspectSlots()
    if not _G.InspectPaperDollItemsFrame then
        return
    end

    for _, slot in next, { _G.InspectPaperDollItemsFrame:GetChildren() } do
        if slot and slot.GetID then
            self:UpdateInspectSlotUpgradeText(slot)
        end
    end
end

function HLY:ADDON_LOADED(_, addonName)
    if addonName == "Bagnon" or addonName == "Bagnon_Bank" then
        self:SetupBagnonHooks()
        self:QueueBagRefresh()
    end

    if addonName ~= "Blizzard_InspectUI" then
        if self.inspectUpgradeHooked and self.inspectCompareHooksSet and (not self.waitingForBagnonHooks or self.bagnonHooksSet) then
            self:UnregisterEvent("ADDON_LOADED")
        end
        return
    end

    if _G.InspectPaperDollItemSlotButton_Update and not self.inspectUpgradeHooked then
        hooksecurefunc("InspectPaperDollItemSlotButton_Update", function(slot)
            if self.db then
                self:UpdateInspectSlotUpgradeText(slot)
            end
        end)
        self.inspectUpgradeHooked = true
    end

    self:SetupInspectCompareHooks()
    self:RefreshInspectSlots()
    self:RefreshCompareStats()

    if self.inspectUpgradeHooked and self.inspectCompareHooksSet and (not self.waitingForBagnonHooks or self.bagnonHooksSet) then
        self:UnregisterEvent("ADDON_LOADED")
    end
end

function HLY:SetupUpgradeTrackHooks()
    if self.upgradeHooksSet then
        return
    end

    hooksecurefunc("PaperDollItemSlotButton_Update", function(slot)
        if self.db then
            self:UpdateCharacterSlotUpgradeText(slot)
        end
    end)

    if _G.InspectPaperDollItemSlotButton_Update then
        hooksecurefunc("InspectPaperDollItemSlotButton_Update", function(slot)
            if self.db then
                self:UpdateInspectSlotUpgradeText(slot)
            end
        end)
        self.inspectUpgradeHooked = true
    else
        self:RegisterEvent("ADDON_LOADED")
    end

    if not self.inspectCompareHooksSet then
        self:RegisterEvent("ADDON_LOADED")
    end

    self.upgradeHooksSet = true
end

-- LibHLYUI options pane (v2) ------------------------------------------------
local UT_ANCHORS = { "TOPLEFT", "TOP", "TOPRIGHT", "LEFT", "CENTER", "RIGHT", "BOTTOMLEFT", "BOTTOM", "BOTTOMRIGHT" }
local UT_TRACKS = {
    { key = "explorer",   label = "Explorer" },
    { key = "adventurer", label = "Adventurer" },
    { key = "veteran",    label = "Veteran" },
    { key = "champion",   label = "Champion" },
    { key = "hero",       label = "Hero" },
    { key = "mythic",     label = "Mythic" },
}

local function UT_TextPane(self, db, refresh)
    return function(p)
        p:Checkbox({ label = "Enable", get = function() return db().enabled end, set = function(v) db().enabled = v refresh() end })
        p:Checkbox({ label = "Show Track Letter", get = function() return db().showInitial end, set = function(v) db().showInitial = v refresh() end })
        p:Dropdown({ label = "Anchor", values = UT_ANCHORS, get = function() return db().anchor end, set = function(v) db().anchor = v refresh() end })
        p:Row({
            function(c) c:Slider({ label = "X Offset", min = -30, max = 30, step = 1, labelWidth = 90, get = function() return db().xOffset end, set = function(v) db().xOffset = v refresh() end }) end,
            function(c) c:Slider({ label = "Y Offset", min = -30, max = 30, step = 1, labelWidth = 90, get = function() return db().yOffset end, set = function(v) db().yOffset = v refresh() end }) end,
        })
        p:Dropdown({ label = "Font", fontPreview = true, values = function() return self:GetFontList() end, get = function() return db().font end, set = function(v) db().font = v refresh() end })
        p:Slider({ label = "Font Size", min = 6, max = 24, step = 1, get = function() return db().fontSize end, set = function(v) db().fontSize = v refresh() end })
    end
end

function HLY:BuildUpgradeTrackOptions(tab)
    tab:Note("Zeigt Aufwertungsstufen (Explorer/Adventurer/Veteran/Champion/Hero/Mythic) auf Taschen-, Charakter- und Inspect-Itemslots an.")
    tab:Checkbox({
        label = "Enable",
        get = function() return self.db.enabled end,
        set = function(v)
            self.db.enabled = v
            self:RefreshAllSlots() self:RefreshCharacterSlots() self:RefreshInspectSlots()
        end,
    })
    tab:TabGroup({
        {
            name = "Bags",
            build = UT_TextPane(self, function() return self.db.bagText end, function() self:RefreshAllSlots() end),
        },
        {
            name = "Character / Inspect",
            build = UT_TextPane(self, function() return self.db.characterText end, function() self:RefreshCharacterSlots() end),
        },
        {
            name = "Track Colors",
            build = function(p)
                for i = 1, #UT_TRACKS, 2 do
                    local a, b = UT_TRACKS[i], UT_TRACKS[i + 1]
                    local builders = {
                        function(c) c:Color({ label = a.label, labelWidth = 90,
                            get = function() local k = self.db.bagText.colors[a.key] return k.r, k.g, k.b end,
                            set = function(r, g, bb) local k = self.db.bagText.colors[a.key] k.r, k.g, k.b = r, g, bb self:RefreshAllSlots() self:RefreshCharacterSlots() self:RefreshInspectSlots() end }) end,
                    }
                    if b then
                        builders[2] = function(c) c:Color({ label = b.label, labelWidth = 90,
                            get = function() local k = self.db.bagText.colors[b.key] return k.r, k.g, k.b end,
                            set = function(r, g, bb) local k = self.db.bagText.colors[b.key] k.r, k.g, k.b = r, g, bb self:RefreshAllSlots() self:RefreshCharacterSlots() self:RefreshInspectSlots() end }) end
                    end
                    p:Row(builders, 2)
                end
            end,
        },
    })
end

addon.options = addon.options or {}
addon.options[#addon.options + 1] = {
    parent = "UI", parentOrder = 100, group = "Gear", groupOrder = 1, name = "Upgrade Track", order = 1,
    build = "BuildUpgradeTrackOptions",
}
