local addonName, addon = ...
local frame = CreateFrame("Frame")
frame:RegisterEvent("PLAYER_LOGIN")
frame:RegisterEvent("INSPECT_READY")
frame:RegisterEvent("GET_ITEM_INFO_RECEIVED")
frame:RegisterEvent("CHAT_MSG_ADDON")

-- Default Settings
local defaults = {
    autoInspect = true,
    showGS = true,
    showiLvl = true,
    showTalents = true,
    showOverlay = true,
    language = "Auto",
    minimapPos = 45 -- degrees
}

-- Addon Communication
local COMM_PREFIX = "RLGearscore"
local RegisterPrefix = C_ChatInfo and C_ChatInfo.RegisterAddonMessagePrefix or RegisterAddonMessagePrefix
local SendAddonMessage = C_ChatInfo and C_ChatInfo.SendAddonMessage or SendAddonMessage

if RegisterPrefix then
    RegisterPrefix(COMM_PREFIX)
end

local langCache = {}
local queryCooldown = {}
local pendingQueries = {}

local ROLE_ICON_TCOORDS = {
    TANK = {0, 0.25, 0, 0.25},
    HEALER = {0.25, 0.5, 0, 0.25},
    DAMAGER = {0.5, 0.75, 0, 0.25}
}

local ROLE_NAMES = {
    TANK = TANK or "Tank",
    HEALER = HEALER or "Heiler",
    DAMAGER = DAMAGER or "Schaden"
}

-- Suppress "Player not found" and "out of range" spam when sending Addon Messages and inspecting
if ChatFrame_AddMessageEventFilter then
    ChatFrame_AddMessageEventFilter("CHAT_MSG_SYSTEM", function(self, event, msg)
        if not msg then return false end
        local now = GetTime()
        
        -- Suppress "Target is too far away" / "out of range" errors during inspect
        local lowerMsg = string.lower(msg)
        if string.find(lowerMsg, "too far", 1, true) or 
           string.find(lowerMsg, "außer reichweite", 1, true) or
           string.find(lowerMsg, "out of range", 1, true) or
           string.find(lowerMsg, "zu weit", 1, true) or
           string.find(lowerMsg, "distance", 1, true) then
            return true
        end
        
        for target, time in pairs(pendingQueries) do
            -- Cleanup stale entries
            if now - time > 5 then
                pendingQueries[target] = nil
            else
                -- Robust check: Does the message contain the target name?
                -- And does it look like a "not found" error?
                -- We use the localized ERR_CHAT_PLAYER_NOT_FOUND_S pattern if possible,
                -- or just check if it contains the name and "not found" keywords (risky with localization).
                -- Better: Just check if the message contains the Name we queried.
                
                local name = strsplit("-", target)
                if string.find(string.lower(msg), string.lower(name), 1, true) then
                    -- If it matches the standard error pattern roughly (optional safety)
                    -- For now, if we just queried them and got a system msg with their name, 
                    -- it's 99% the error.
                    pendingQueries[target] = nil
                    return true
                end
            end
        end
        return false
    end)
end

-- Suppress UI Error Messages (red text) for range-related errors
-- Completely override AddMessage to ensure all range errors are blocked
if UIErrorsFrame then
    local originalAddMessage = UIErrorsFrame.AddMessage
    UIErrorsFrame.AddMessage = function(self, message, r, g, b, id, addToStart)
        if not message then 
            return originalAddMessage(self, message, r, g, b, id, addToStart)
        end
        local lowerMsg = string.lower(message)
        
        -- Suppress all range-related error messages
        if string.find(lowerMsg, "target is too far away", 1, true) or
           string.find(lowerMsg, "target out of range", 1, true) or
           string.find(lowerMsg, "zu weit entfernt", 1, true) or
           string.find(lowerMsg, "außer reichweite", 1, true) or
           string.find(lowerMsg, "too far away", 1, true) or
           string.find(lowerMsg, "out of range", 1, true) or
           string.find(lowerMsg, "zu weit", 1, true) or
           string.find(lowerMsg, "entfernt", 1, true) then
            -- Don't display this error
            return
        end
        
        -- Pass through all other messages
        return originalAddMessage(self, message, r, g, b, id, addToStart)
    end
end

local function GetLanguageFlag(lang)
    if not lang then return "|cff808080[?]|r" end -- Grey [?] for unknown/pending
    -- Text-based flags for now
    if lang == "deDE" then return "|cff000000[|r|cffff0000D|r|cffffcc00E|r|cff000000]|r" end
    if lang == "enUS" or lang == "enGB" then return "|cff0000ff[|r|cffffffffE|r|cffff0000N|r|cff0000ff]|r" end
    if lang == "ruRU" then return "|cffffffff[|r|cff0000ffR|r|cffff0000U|r|cffffffff]|r" end
    if lang == "frFR" then return "|cff0000ff[|r|cffffffffF|r|cffff0000R|r|cff0000ff]|r" end
    if lang == "esES" or lang == "esMX" then return "|cffff0000[|r|cffffcc00E|r|cffff0000S|r|cffff0000]|r" end
    if lang == "itIT" then return "|cff009900[|r|cffffffffI|r|cffff0000T|r|cff009900]|r" end
    if lang == "ptBR" then return "|cff009900[|r|cffffcc00B|r|cff0000ffR|r|cff009900]|r" end
    if lang == "koKR" then return "[KR]" end
    if lang == "zhCN" or lang == "zhTW" then return "[CN]" end
    return "[" .. lang .. "]"
end

-- Realm Language Database (Compact)
local RealmData = {
    -- German (deDE)
    ["Aegwynn"] = "deDE", ["Alexstrasza"] = "deDE", ["Alleria"] = "deDE", ["Aman'Thul"] = "deDE", 
    ["Ambossar"] = "deDE", ["Anetheron"] = "deDE", ["Antonidas"] = "deDE", ["Anub'arak"] = "deDE", 
    ["Area 52"] = "deDE", ["Arthas"] = "deDE", ["Arygos"] = "deDE", ["Azshara"] = "deDE", 
    ["Baelgun"] = "deDE", ["Blackhand"] = "deDE", ["Blackmoore"] = "deDE", ["Blackrock"] = "deDE", 
    ["Blutkessel"] = "deDE", ["Dalvengyr"] = "deDE", ["Das Konsortium"] = "deDE", ["Das Syndikat"] = "deDE", 
    ["Der Mithrilorden"] = "deDE", ["Der Rat von Dalaran"] = "deDE", ["Destromath"] = "deDE", ["Dethecus"] = "deDE", 
    ["Die Aldor"] = "deDE", ["Die Arguswacht"] = "deDE", ["Die Ewige Wacht"] = "deDE", ["Die Nachtwache"] = "deDE", 
    ["Die Silberne Hand"] = "deDE", ["Die Todeskrallen"] = "deDE", ["Dun Morogh"] = "deDE", ["Durotan"] = "deDE", 
    ["Echsenkessel"] = "deDE", ["Eredar"] = "deDE", ["Festung der Stürme"] = "deDE", ["Forscherliga"] = "deDE", 
    ["Frostmourne"] = "deDE", ["Frostwolf"] = "deDE", ["Garrosh"] = "deDE", ["Gilneas"] = "deDE", 
    ["Gorgonnash"] = "deDE", ["Gul'dan"] = "deDE", ["Kel'Thuzad"] = "deDE", ["Khaz'goroth"] = "deDE", 
    ["Kil'Jaeden"] = "deDE", ["Krag'jin"] = "deDE", ["Kult der Verdammten"] = "deDE", ["Lordaeron"] = "deDE", 
    ["Lothar"] = "deDE", ["Madmortem"] = "deDE", ["Mal'Ganis"] = "deDE", ["Malfurion"] = "deDE", 
    ["Mannoroth"] = "deDE", ["Minahonda"] = "deDE", ["Malygos"] = "deDE", ["Mug'thol"] = "deDE", 
    ["Nathrezim"] = "deDE", ["Nazjatar"] = "deDE", ["Nefarian"] = "deDE", ["Nera'thor"] = "deDE", 
    ["Nethersturm"] = "deDE", ["Norgannon"] = "deDE", ["Nozdormu"] = "deDE", ["Onyxia"] = "deDE", 
    ["Perenolde"] = "deDE", ["Proudmoore"] = "deDE", ["Rajaxx"] = "deDE", ["Rexxar"] = "deDE", 
    ["Sen'jin"] = "deDE", ["Shattrath"] = "deDE", ["Shen'dralar"] = "deDE", ["Silberne Hand"] = "deDE", 
    ["Terrordar"] = "deDE", ["Theradras"] = "deDE", ["Thrall"] = "deDE", ["Tirion"] = "deDE", 
    ["Tichondrius"] = "deDE", ["Teldrassil"] = "deDE", ["Un'Goro"] = "deDE", ["Vek'lor"] = "deDE", 
    ["Wrathbringer"] = "deDE", ["Ysera"] = "deDE", ["Zirkel des Cenarius"] = "deDE", ["Zuluhed"] = "deDE",
    ["Everlook"] = "deDE", ["Lakeshire"] = "deDE", ["Razorfen"] = "deDE", ["Venoxis"] = "deDE", 
    ["Patchwerk"] = "deDE", ["Transcendence"] = "deDE", ["Heartstriker"] = "deDE", ["Dragon's Call"] = "deDE", 
    ["Lucifron"] = "deDE", ["Celebras"] = "deDE", ["Skullflame"] = "deDE",

    -- Russian (ruRU)
    ["Azuregos"] = "ruRU", ["Borean Tundra"] = "ruRU", ["Blackscar"] = "ruRU", ["Booty Bay"] = "ruRU", 
    ["Deathguard"] = "ruRU", ["Deepholm"] = "ruRU", ["Eversong"] = "ruRU", ["Galakrond"] = "ruRU", 
    ["Goldrinn"] = "ruRU", ["Gordunni"] = "ruRU", ["Greymane"] = "ruRU", ["Grom"] = "ruRU", 
    ["Howling Fjord"] = "ruRU", ["Lich King"] = "ruRU", ["Razuvious"] = "ruRU", ["Soulflayer"] = "ruRU", 
    ["Thermaplugg"] = "ruRU", ["Fordragon"] = "ruRU", ["Flamegor"] = "ruRU", ["Chromie"] = "ruRU", 
    ["Wyrmthalak"] = "ruRU", ["Rhok'delar"] = "ruRU",

    -- French (frFR)
    ["Arak-arahm"] = "frFR", ["Arathi"] = "frFR", ["Archimonde"] = "frFR", ["Chants éternels"] = "frFR", 
    ["Cho'gall"] = "frFR", ["Dalaran"] = "frFR", ["Drek'Thar"] = "frFR", ["Eitrigg"] = "frFR", 
    ["Eldre'Thalas"] = "frFR", ["Elune"] = "frFR", ["Garona"] = "frFR", ["Hyjal"] = "frFR", 
    ["Illidan"] = "frFR", ["Kael'thas"] = "frFR", ["Khaz Modan"] = "frFR", ["Kirin Tor"] = "frFR", 
    ["Krasus"] = "frFR", ["Les Clairvoyants"] = "frFR", ["Les Sentinelles"] = "frFR", ["Marécage de Zangar"] = "frFR", 
    ["Medivh"] = "frFR", ["Naxxramas"] = "frFR", ["Ner'zhul"] = "frFR", ["Rashgarroth"] = "frFR", 
    ["Sargeras"] = "frFR", ["Sinstralis"] = "frFR", ["Suramar"] = "frFR", ["Temple noir"] = "frFR", 
    ["Throk'Feroth"] = "frFR", ["Uldaman"] = "frFR", ["Varimathras"] = "frFR", ["Vol'jin"] = "frFR", 
    ["Ysondre"] = "frFR", ["Auberdine"] = "frFR", ["Sulfuron"] = "frFR", ["Finkle"] = "frFR", ["Amnennar"] = "frFR",

    -- Spanish (esES)
    ["Aggramar"] = "esES", ["Colinas Pardas"] = "esES", ["C'Thun"] = "esES", ["Dun Modr"] = "esES", 
    ["Exodar"] = "esES", ["Los Errantes"] = "esES", ["Minahonda"] = "esES", ["Sanguino"] = "esES", 
    ["Shen'dralar"] = "esES", ["Tyrande"] = "esES", ["Uldum"] = "esES", ["Zul'jin"] = "esES", 
    ["Mandokir"] = "esES"
}

-- Options Frame (Modern Dark UI like RLRaidDungeonReset)
local optionsFrame
local settingsPanel, aboutPanel

local function CreateOptionsFrame()
    if optionsFrame then
        optionsFrame:Show()
        return
    end
    
    local f = CreateFrame("Frame", "RLGearscoreOptions", UIParent)
    optionsFrame = f
    f:SetSize(400, 450)
    f:SetPoint("CENTER")
    f:SetFrameStrata("HIGH")
    f:SetMovable(true)
    f:EnableMouse(true)
    f:RegisterForDrag("LeftButton")
    f:SetScript("OnDragStart", function(self) self:StartMoving() end)
    f:SetScript("OnDragStop", function(self) self:StopMovingOrSizing() end)
    
    -- Modern dark background
    local bg = f:CreateTexture(nil, "BACKGROUND")
    bg:SetAllPoints()
    bg:SetColorTexture(0.1, 0.1, 0.12, 0.95)
    f.bg = bg
    
    -- Border (simple colored border)
    local border = f:CreateTexture(nil, "BACKGROUND")
    border:SetPoint("TOPLEFT", f, "TOPLEFT", -2, 2)
    border:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", 2, -2)
    border:SetColorTexture(0.3, 0.3, 0.35, 1)
    f.border = border
    
    -- Header background
    local headerBg = f:CreateTexture(nil, "ARTWORK")
    headerBg:SetPoint("TOPLEFT")
    headerBg:SetPoint("TOPRIGHT")
    headerBg:SetHeight(40)
    headerBg:SetColorTexture(0.2, 0.2, 0.25, 1)
    f.headerBg = headerBg
    
    -- Title
    f.title = f:CreateFontString(nil, "OVERLAY", "GameFontHighlightLarge")
    f.title:SetPoint("LEFT", f, "TOPLEFT", 16, -12)
    f.title:SetText(addon.L["OPTIONS_TITLE"])
    
    -- Close Button (custom)
    local closeBtn = CreateFrame("Button", nil, f)
    closeBtn:SetSize(28, 28)
    closeBtn:SetPoint("TOPRIGHT", f, "TOPRIGHT", -8, -6)
    
    local closeBtnBg = closeBtn:CreateTexture(nil, "BACKGROUND")
    closeBtnBg:SetAllPoints()
    closeBtnBg:SetColorTexture(0.3, 0.3, 0.35, 1)
    closeBtn.bg = closeBtnBg
    
    local closeBtnText = closeBtn:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
    closeBtnText:SetPoint("CENTER", closeBtn, "CENTER", 0, 1)
    closeBtnText:SetText("X")
    closeBtn.text = closeBtnText
    
    closeBtn:SetScript("OnEnter", function(self)
        self.bg:SetColorTexture(0.6, 0.2, 0.2, 1)
    end)
    closeBtn:SetScript("OnLeave", function(self)
        self.bg:SetColorTexture(0.3, 0.3, 0.35, 1)
    end)
    closeBtn:SetScript("OnClick", function()
        f:Hide()
    end)
    
    -- Tabs (custom modern style)
    local function createTab(name, text, xOffset)
        local tab = CreateFrame("Button", name, f)
        tab:SetSize(100, 28)
        tab:SetPoint("TOPLEFT", f, "TOPLEFT", xOffset, -48)
        
        local tabBg = tab:CreateTexture(nil, "BACKGROUND")
        tabBg:SetAllPoints()
        tabBg:SetColorTexture(0.15, 0.15, 0.18, 1)
        tab.bg = tabBg
        
        local tabText = tab:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
        tabText:SetPoint("CENTER", tab, "CENTER", 0, 0)
        tabText:SetText(text)
        tab.text = tabText
        
        tab:SetScript("OnEnter", function(self)
            self.bg:SetColorTexture(0.25, 0.25, 0.3, 1)
        end)
        tab:SetScript("OnLeave", function(self)
            if not self.disabled then
                self.bg:SetColorTexture(0.15, 0.15, 0.18, 1)
            end
        end)
        
        return tab
    end
    
    local tabSettings = createTab("RLGearscoreTabSettings", addon.L["TAB_SETTINGS"], 16)
    local tabAbout = createTab("RLGearscoreTabAbout", addon.L["TAB_ABOUT"], 120)
    
    -- Content Pages
    settingsPanel = CreateFrame("Frame", nil, f)
    settingsPanel:SetPoint("TOPLEFT", f, "TOPLEFT", 16, -84)
    settingsPanel:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", -16, 16)
    
    aboutPanel = CreateFrame("Frame", nil, f)
    aboutPanel:SetPoint("TOPLEFT", f, "TOPLEFT", 16, -84)
    aboutPanel:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", -16, 16)
    aboutPanel:Hide()
    
    -- === Settings Panel Content ===
    
    -- Checkboxes
    local function CreateCheckbox(key, labelText, relativeTo, yOffset)
        local cb = CreateFrame("CheckButton", nil, settingsPanel, "ChatConfigCheckButtonTemplate")
        if relativeTo then
             cb:SetPoint("TOPLEFT", relativeTo, "BOTTOMLEFT", 0, yOffset)
        else
             cb:SetPoint("TOPLEFT", 16, yOffset)
        end
        cb.Text:SetText(labelText)
        cb:SetChecked(GearScoreDB[key])
        cb:SetScript("OnClick", function(self)
            GearScoreDB[key] = self:GetChecked()
        end)
        return cb
    end

    local cb1 = CreateCheckbox("showGS", addon.L["ENABLE_GS"], nil, 0)
    settingsPanel.cb1 = cb1
    
    local cb2 = CreateCheckbox("showiLvl", addon.L["ENABLE_ILVL"], cb1, -10)
    settingsPanel.cb2 = cb2
    
    local cb3 = CreateCheckbox("showTalents", addon.L["ENABLE_TALENTS"], cb2, -10)
    settingsPanel.cb3 = cb3
    
    local cb4 = CreateCheckbox("autoInspect", addon.L["ENABLE_AUTO_INSPECT"], cb3, -10)
    settingsPanel.cb4 = cb4

    local cb5 = CreateCheckbox("showOverlay", addon.L["ENABLE_OVERLAY"], cb4, -10)
    settingsPanel.cb5 = cb5

    -- Language Dropdown
    local langLabel = settingsPanel:CreateFontString(nil, "ARTWORK", "GameFontNormal")
    langLabel:SetPoint("TOPLEFT", cb5, "BOTTOMLEFT", 0, -20)
    langLabel:SetText(addon.L["LANGUAGE"])
    settingsPanel.langLabel = langLabel

    local dropDown = CreateFrame("Frame", "RLGearscoreLangDropDown", settingsPanel, "UIDropDownMenuTemplate")
    dropDown:SetPoint("TOPLEFT", langLabel, "BOTTOMLEFT", -15, -10)
    UIDropDownMenu_SetWidth(dropDown, 150)
    UIDropDownMenu_SetText(dropDown, GearScoreDB.language or "Auto")

    local langs = { "Auto", "enUS", "deDE", "ruRU" }
    
    UIDropDownMenu_Initialize(dropDown, function(self, level, menuList)
        local info = UIDropDownMenu_CreateInfo()
        for _, lang in ipairs(langs) do
            info.text = lang
            info.checked = (GearScoreDB.language == lang)
            info.func = function()
                GearScoreDB.language = lang
                UIDropDownMenu_SetText(dropDown, lang)
                addon:SetLanguage(lang)
                -- Update UI texts
                f.title:SetText(addon.L["OPTIONS_TITLE"])
                tabSettings.text:SetText(addon.L["TAB_SETTINGS"])
                tabAbout.text:SetText(addon.L["TAB_ABOUT"])
                settingsPanel.cb1.Text:SetText(addon.L["ENABLE_GS"])
                settingsPanel.cb2.Text:SetText(addon.L["ENABLE_ILVL"])
                settingsPanel.cb3.Text:SetText(addon.L["ENABLE_TALENTS"])
                settingsPanel.cb4.Text:SetText(addon.L["ENABLE_AUTO_INSPECT"])
                settingsPanel.cb5.Text:SetText(addon.L["ENABLE_OVERLAY"])
                settingsPanel.langLabel:SetText(addon.L["LANGUAGE"])
                -- Update About texts
                aboutPanel.copyHeader:SetText(addon.L["COPYRIGHT_HEADER"])
                aboutPanel.creditsHeader:SetText(addon.L["CREDITS_HEADER"])
                aboutPanel.creditsText:SetText(addon.L["CREDITS_TEXT"])
                
                print("|cffffd100RLGearscore:|r " .. addon.L["LOADED_MESSAGE"])
            end
            UIDropDownMenu_AddButton(info)
        end
    end)
    
    -- === About Panel Content ===
    
    -- Logo
    local logo = aboutPanel:CreateTexture(nil, "ARTWORK")
    logo:SetTexture("Interface\\AddOns\\RLGearscore\\img\\logo.png")
    logo:SetSize(64, 64)
    logo:SetPoint("TOP", 0, -10)
    
    -- Copyright Header
    local copyHeader = aboutPanel:CreateFontString(nil, "ARTWORK", "GameFontNormalLarge")
    copyHeader:SetPoint("TOP", logo, "BOTTOM", 0, -10)
    copyHeader:SetText(addon.L["COPYRIGHT_HEADER"])
    aboutPanel.copyHeader = copyHeader
    
    -- Copyright Text
    local copyText = aboutPanel:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
    copyText:SetPoint("TOP", copyHeader, "BOTTOM", 0, -5)
    copyText:SetWidth(360)
    copyText:SetJustifyH("CENTER")
    copyText:SetText(addon.L["ABOUT_CONTACT_INFO"])
    
    -- Git URL
    local gitEditBox = CreateFrame("EditBox", nil, aboutPanel, "InputBoxTemplate")
    gitEditBox:SetSize(350, 20)
    gitEditBox:SetPoint("TOP", copyText, "BOTTOM", 5, -10)
    gitEditBox:SetAutoFocus(false)
    gitEditBox:SetText("git clone https://rl-dev.de/git/RLGearscore.git")
    gitEditBox:SetCursorPosition(0)
    
    -- Credits Header
    local creditsHeader = aboutPanel:CreateFontString(nil, "ARTWORK", "GameFontNormalLarge")
    creditsHeader:SetPoint("TOP", gitEditBox, "BOTTOM", 0, -20)
    creditsHeader:SetText(addon.L["CREDITS_HEADER"])
    aboutPanel.creditsHeader = creditsHeader
    
    -- Credits Text
    local creditsText = aboutPanel:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
    creditsText:SetPoint("TOP", creditsHeader, "BOTTOM", 0, -5)
    creditsText:SetWidth(360)
    creditsText:SetJustifyH("CENTER")
    creditsText:SetText(addon.L["CREDITS_TEXT"])
    aboutPanel.creditsText = creditsText
    
    -- Link
    local linkEditBox = CreateFrame("EditBox", nil, aboutPanel, "InputBoxTemplate")
    linkEditBox:SetSize(350, 20)
    linkEditBox:SetPoint("TOP", creditsText, "BOTTOM", 5, -5)
    linkEditBox:SetAutoFocus(false)
    linkEditBox:SetText("https://github.com/Hubbotu/Gearscore/blob/main/ruRU.lua")
    linkEditBox:SetCursorPosition(0)
    
    -- Tab Logic
    local function setTab(mode)
        settingsPanel:Hide()
        aboutPanel:Hide()
        
        -- Reset all tabs
        tabSettings.disabled = false
        tabSettings.bg:SetColorTexture(0.15, 0.15, 0.18, 1)
        tabSettings.text:SetTextColor(1, 1, 1)
        
        tabAbout.disabled = false
        tabAbout.bg:SetColorTexture(0.15, 0.15, 0.18, 1)
        tabAbout.text:SetTextColor(1, 1, 1)
        
        if mode == "settings" then
            settingsPanel:Show()
            tabSettings.disabled = true
            tabSettings.bg:SetColorTexture(0.4, 0.4, 0.5, 1)
            tabSettings.text:SetTextColor(1, 0.82, 0)
        else
            aboutPanel:Show()
            tabAbout.disabled = true
            tabAbout.bg:SetColorTexture(0.4, 0.4, 0.5, 1)
            tabAbout.text:SetTextColor(1, 0.82, 0)
        end
    end
    
    tabSettings:SetScript("OnClick", function() setTab("settings") end)
    tabAbout:SetScript("OnClick", function() setTab("about") end)
    
    setTab("settings")
end

-- Minimap Button (Modern style like RLRaidDungeonReset)
local minimapBtn
local function CreateMinimapButton()
    if minimapBtn or not Minimap then return end
    
    local btn = CreateFrame("Button", "RLGearscoreMinimapButton", Minimap)
    minimapBtn = btn
    btn:SetSize(36, 36)
    btn:SetFrameStrata("HIGH")
    btn:SetMovable(true)
    btn:EnableMouse(true)
    btn:SetClampedToScreen(true)
    btn:RegisterForClicks("LeftButtonUp", "RightButtonUp")
    
    -- Border
    local border = btn:CreateTexture(nil, "OVERLAY")
    border:SetTexture("Interface\\Minimap\\MiniMap-TrackingBorder")
    border:SetSize(54, 54)
    border:SetPoint("TOPLEFT")
    btn.border = border
    
    -- Icon
    local tex = btn:CreateTexture(nil, "ARTWORK")
    tex:SetSize(22, 22)
    tex:SetPoint("CENTER")
    tex:SetTexture("Interface\\AddOns\\RLGearscore\\img\\logo.png")
    btn.icon = tex
    
    -- Highlight texture
    local highlight = btn:CreateTexture(nil, "HIGHLIGHT")
    highlight:SetAllPoints()
    highlight:SetColorTexture(1, 1, 1, 0.3)
    btn:SetHighlightTexture(highlight)
    
    -- Pushed texture
    local pushed = btn:CreateTexture(nil, "ARTWORK")
    pushed:SetAllPoints()
    pushed:SetColorTexture(0.5, 0.5, 0.5, 0.5)
    pushed:Hide()
    btn.pushed = pushed
    
    local function UpdatePosition()
        local angle = math.rad(GearScoreDB.minimapPos or 45)
        local x = math.cos(angle) * 80
        local y = math.sin(angle) * 80
        btn:ClearAllPoints()
        btn:SetPoint("CENTER", Minimap, "CENTER", x, y)
    end
    
    btn:SetScript("OnEnter", function(self)
        GameTooltip:SetOwner(self, "ANCHOR_LEFT")
        GameTooltip:SetText("RLGearscore")
        GameTooltip:AddLine(addon.L["MINIMAP_BUTTON_TOOLTIP"], 1, 1, 1)
        GameTooltip:Show()
    end)
    
    btn:SetScript("OnLeave", function(self)
        GameTooltip:Hide()
    end)
    
    btn:SetScript("OnMouseDown", function(self, button)
        if button == "LeftButton" then
            self.pushed:Show()
            self.icon:SetPoint("CENTER", self, "CENTER", 1, -1)
        end
    end)
    
    btn:SetScript("OnMouseUp", function(self, button)
        self.pushed:Hide()
        self.icon:SetPoint("CENTER", self, "CENTER", 0, 0)
    end)
    
    btn:SetScript("OnClick", function(self, button)
        if button == "RightButton" then
            -- Right click to toggle visibility (optional feature)
            -- For now, just open options
            if not optionsFrame then CreateOptionsFrame() end
            if optionsFrame:IsShown() then optionsFrame:Hide() else optionsFrame:Show() end
        else
            if not optionsFrame then CreateOptionsFrame() end
            if optionsFrame:IsShown() then optionsFrame:Hide() else optionsFrame:Show() end
        end
    end)
    
    btn:RegisterForDrag("LeftButton")
    btn:SetScript("OnDragStart", function(self)
        self:StartMoving()
    end)
    
    btn:SetScript("OnDragStop", function(self)
        self:StopMovingOrSizing()
        local mx, my = Minimap:GetCenter()
        local cx, cy = self:GetCenter()
        local scale = Minimap:GetEffectiveScale()
        cx, cy = cx / scale, cy / scale
        local dx, dy = cx - mx, cy - my
        local angle = math.deg(math.atan2(dy, dx))
        GearScoreDB.minimapPos = angle
        UpdatePosition()
    end)
    
    UpdatePosition()
end

-- Helper: GetTooltipUnit
local function GetTooltipUnit(tooltip)
    local _, unit = tooltip:GetUnit()
    
    -- Retail support for GetMouseFoci
    if not unit and GetMouseFoci then
        local foci = GetMouseFoci()
        local mouseFocus = foci and foci[1]
        if mouseFocus and mouseFocus.GetAttribute then
            unit = mouseFocus:GetAttribute("unit")
        end
    end
    
    -- Classic / Legacy support
    if not unit and GetMouseFocus then
        local mouseFocus = GetMouseFocus()
        if mouseFocus and mouseFocus.GetAttribute then
            unit = mouseFocus:GetAttribute("unit")
        end
    end
    
    if not unit and UnitExists("mouseover") then unit = "mouseover" end
    if not unit or not UnitIsPlayer(unit) then return nil end
    return unit
end

-- DB Handling
function frame:OnEvent(event, ...)
    local arg1, arg2, arg3, arg4 = ...
    if event == "PLAYER_LOGIN" then
        if not GearScoreDB then GearScoreDB = {} end
        for k, v in pairs(defaults) do
            if GearScoreDB[k] == nil then GearScoreDB[k] = v end
        end
        
        -- Apply Language
        addon:SetLanguage(GearScoreDB.language)
        
        -- Init UI
        CreateMinimapButton()
        
        print("|cffffd100" .. addon.L["GEARSCORE_LABEL"] .. "|r " .. addon.L["LOADED_MESSAGE"])
    elseif event == "CHAT_MSG_ADDON" then
        local prefix, msg, channel, sender = arg1, arg2, arg3, arg4
        if prefix == COMM_PREFIX then
             -- Handle QUERY
             if msg == "QUERY" then
                 -- Send my language
                 local myLang = GearScoreDB.language
                 if not myLang or myLang == "Auto" then myLang = GetLocale() end
                 -- Reply to sender
                 if sender then
                     SendAddonMessage(COMM_PREFIX, "ANS:" .. myLang, "WHISPER", sender)
                 end
             -- Handle ANSWER
             elseif msg:sub(1, 4) == "ANS:" then
                 local lang = msg:sub(5)
                 if sender and lang then
                     -- Cache by full sender name (Name-Realm)
                     langCache[sender] = lang
                     
                     -- Also cache by short name (Name) for local realm lookups
                     local shortName = sender
                     if Ambiguate then
                        shortName = Ambiguate(sender, "none")
                     elseif string.find(sender, "-") then
                        shortName = string.match(sender, "^(.-)-")
                     end

                     if shortName and shortName ~= sender then
                         langCache[shortName] = lang
                     end
                     
                     -- Update tooltip if currently hovering this sender
                     if GameTooltip:IsVisible() then
                         local unit = GetTooltipUnit(GameTooltip)
                         if unit then
                             local name, realm = UnitName(unit)
                             -- Check if this unit matches the sender (short or long)
                             if name == shortName then
                                 GameTooltip:SetUnit(unit)
                             end
                         end
                     end
                 end
             end
        end
    elseif event == "INSPECT_READY" then
        self:INSPECT_READY(event, arg1)
    elseif event == "GET_ITEM_INFO_RECEIVED" then
        self:GET_ITEM_INFO_RECEIVED(event, arg1, arg2)
    end
end
frame:SetScript("OnEvent", frame.OnEvent)

-- Helper: GetTabPoints (Handles API variations)
local function GetTabPoints(tabIndex, isInspect)
    if not GetTalentTabInfo then return 0, nil end
    local t1, t2, t3, t4, t5 = GetTalentTabInfo(tabIndex, isInspect)
    -- If first return is a number (ID), it's the new API: id, name, desc, icon, points
    if type(t1) == "number" then
        return tonumber(t5) or 0, t2 -- Return points and name (t2)
    else
        -- Old API: name, icon, points, ...
        return tonumber(t3) or 0, t1 -- Return points and name (t1)
    end
end

-- Helper: GetUnitTalentString (Cross-version)
local function GetUnitTalentString(unit, isInspect)
    local talentString = ""
    local validScan = false
    local totalPoints = 0

    if WOW_PROJECT_ID == WOW_PROJECT_MAINLINE then
        -- Retail: Use Specialization
        local specID = 0
        if isInspect then
            specID = GetInspectSpecialization(unit)
        else
            local specIndex = GetSpecialization()
            if specIndex then
                specID = GetSpecializationInfo(specIndex)
            end
        end
        
        if specID and specID > 0 then
            local _, name = GetSpecializationInfoByID(specID)
            talentString = name
            validScan = true
            totalPoints = 1 -- Dummy value to indicate success
        end
    else
        -- Classic / Cata: Use Talent Tabs
        for i = 1, 3 do
            local pointsSpent, name = GetTabPoints(i, isInspect)
            if name then validScan = true end
            totalPoints = totalPoints + pointsSpent
            if i > 1 then talentString = talentString .. "/" end
            talentString = talentString .. pointsSpent
        end
    end
    
    return talentString, validScan, totalPoints
end

-- Helper: SmartInspect
local lastInspectTime = 0
local currentInspectGUID = nil
local function SmartInspect(unit)
    if not unit or not UnitExists(unit) or not UnitIsConnected(unit) or not CanInspect(unit) then return end
    if InspectFrame and InspectFrame:IsShown() then return end
    if InCombatLockdown and InCombatLockdown() then return end
    
    if not GearScoreDB.autoInspect and not IsShiftKeyDown() then return end

    -- Check actual inspect distance (4 = inspect range)
    -- This adapts to renderer settings and actual game distance
    if CheckInteractDistance(unit, 4) then
        local now = GetTime()
        if (now - lastInspectTime > 1.5) then
            lastInspectTime = now
            
            -- Suppress UI errors (red text) during inspect to avoid spam - keep suppressed for 2 seconds
            UIErrorsFrame:UnregisterEvent("UI_ERROR_MESSAGE")
            
            if ClearInspectPlayer then ClearInspectPlayer() end
            NotifyInspect(unit)
            currentInspectGUID = UnitGUID(unit)
            
            C_Timer.After(2.0, function() UIErrorsFrame:RegisterEvent("UI_ERROR_MESSAGE") end)
        else
             -- Retry logic
             local delay = 1.55 - (now - lastInspectTime)
             C_Timer.After(delay, function()
                 if GameTooltip:IsVisible() then
                     local tooltipUnit = GetTooltipUnit(GameTooltip)
                     if tooltipUnit and UnitIsUnit(tooltipUnit, unit) then
                         SmartInspect(unit)
                     end
                 end
             end)
        end
    end
end

-- TacoTip-style GearScore Calculation
local gearCache = {}

-- WoW Version Detection for bracket sizing
local wowVersion, build, date, tocVersion = GetBuildInfo()
local isClassic = tocVersion < 20000
local isTBC = tocVersion >= 20000 and tocVersion < 30000
local isWotLK = tocVersion >= 30000 and tocVersion < 40000

local BRACKET_SIZE = 1000
if isWotLK then
    BRACKET_SIZE = 1000
elseif isTBC then
    BRACKET_SIZE = 400
elseif isClassic then
    BRACKET_SIZE = 200
end

local MAX_SCORE = BRACKET_SIZE * 6 - 1

local GS_ItemTypes = {
    ["INVTYPE_RELIC"] = { ["SlotMOD"] = 0.3164, ["ItemSlot"] = 18 },
    ["INVTYPE_TRINKET"] = { ["SlotMOD"] = 0.5625, ["ItemSlot"] = 33 },
    ["INVTYPE_2HWEAPON"] = { ["SlotMOD"] = 2.000, ["ItemSlot"] = 16 },
    ["INVTYPE_WEAPONMAINHAND"] = { ["SlotMOD"] = 1.0000, ["ItemSlot"] = 16 },
    ["INVTYPE_WEAPONOFFHAND"] = { ["SlotMOD"] = 1.0000, ["ItemSlot"] = 17 },
    ["INVTYPE_RANGED"] = { ["SlotMOD"] = 0.3164, ["ItemSlot"] = 18 },
    ["INVTYPE_THROWN"] = { ["SlotMOD"] = 0.3164, ["ItemSlot"] = 18 },
    ["INVTYPE_RANGEDRIGHT"] = { ["SlotMOD"] = 0.3164, ["ItemSlot"] = 18 },
    ["INVTYPE_SHIELD"] = { ["SlotMOD"] = 1.0000, ["ItemSlot"] = 17 },
    ["INVTYPE_WEAPON"] = { ["SlotMOD"] = 1.0000, ["ItemSlot"] = 36 },
    ["INVTYPE_HOLDABLE"] = { ["SlotMOD"] = 1.0000, ["ItemSlot"] = 17 },
    ["INVTYPE_HEAD"] = { ["SlotMOD"] = 1.0000, ["ItemSlot"] = 1 },
    ["INVTYPE_NECK"] = { ["SlotMOD"] = 0.5625, ["ItemSlot"] = 2 },
    ["INVTYPE_SHOULDER"] = { ["SlotMOD"] = 0.7500, ["ItemSlot"] = 3 },
    ["INVTYPE_CHEST"] = { ["SlotMOD"] = 1.0000, ["ItemSlot"] = 5 },
    ["INVTYPE_ROBE"] = { ["SlotMOD"] = 1.0000, ["ItemSlot"] = 5 },
    ["INVTYPE_WAIST"] = { ["SlotMOD"] = 0.7500, ["ItemSlot"] = 6 },
    ["INVTYPE_LEGS"] = { ["SlotMOD"] = 1.0000, ["ItemSlot"] = 7 },
    ["INVTYPE_FEET"] = { ["SlotMOD"] = 0.75, ["ItemSlot"] = 8 },
    ["INVTYPE_WRIST"] = { ["SlotMOD"] = 0.5625, ["ItemSlot"] = 9 },
    ["INVTYPE_HAND"] = { ["SlotMOD"] = 0.7500, ["ItemSlot"] = 10 },
    ["INVTYPE_FINGER"] = { ["SlotMOD"] = 0.5625, ["ItemSlot"] = 31 },
    ["INVTYPE_CLOAK"] = { ["SlotMOD"] = 0.5625, ["ItemSlot"] = 15 },
    ["INVTYPE_BODY"] = { ["SlotMOD"] = 0, ["ItemSlot"] = 4 },
}

local GS_Formula = {
    ["A"] = {
        [4] = { ["A"] = 91.4500, ["B"] = 0.6500 },
        [3] = { ["A"] = 81.3750, ["B"] = 0.8125 },
        [2] = { ["A"] = 73.0000, ["B"] = 1.0000 }
    },
    ["B"] = {
        [4] = { ["A"] = 26.0000, ["B"] = 1.2000 },
        [3] = { ["A"] = 0.7500, ["B"] = 1.8000 },
        [2] = { ["A"] = 8.0000, ["B"] = 2.0000 },
        [1] = { ["A"] = 0.0000, ["B"] = 2.2500 }
    },
    ["C"] = {
        [4] = { ["A"] = 0.2500, ["B"] = 1.6275 }
    },
}

local GS_Quality = {
    [BRACKET_SIZE*6] = {
        ["Red"] = { ["A"] = 0.94, ["B"] = BRACKET_SIZE*5, ["C"] = 0.00006, ["D"] = 1 },
        ["Blue"] = { ["A"] = 0.47, ["B"] = BRACKET_SIZE*5, ["C"] = 0.00047, ["D"] = -1 },
        ["Green"] = { ["A"] = 0, ["B"] = 0, ["C"] = 0, ["D"] = 0 },
        ["Description"] = "Legendary"
    },
    [BRACKET_SIZE*5] = {
        ["Red"] = { ["A"] = 0.69, ["B"] = BRACKET_SIZE*4, ["C"] = 0.00025, ["D"] = 1 },
        ["Blue"] = { ["A"] = 0.28, ["B"] = BRACKET_SIZE*4, ["C"] = 0.00019, ["D"] = 1 },
        ["Green"] = { ["A"] = 0.97, ["B"] = BRACKET_SIZE*4, ["C"] = 0.00096, ["D"] = -1 },
        ["Description"] = "Epic"
    },
    [BRACKET_SIZE*4] = {
        ["Red"] = { ["A"] = 0.0, ["B"] = BRACKET_SIZE*3, ["C"] = 0.00069, ["D"] = 1 },
        ["Blue"] = { ["A"] = 0.5, ["B"] = BRACKET_SIZE*3, ["C"] = 0.00022, ["D"] = -1 },
        ["Green"] = { ["A"] = 1, ["B"] = BRACKET_SIZE*3, ["C"] = 0.00003, ["D"] = -1 },
        ["Description"] = "Superior"
    },
    [BRACKET_SIZE*3] = {
        ["Red"] = { ["A"] = 0.12, ["B"] = BRACKET_SIZE*2, ["C"] = 0.00012, ["D"] = -1 },
        ["Blue"] = { ["A"] = 1, ["B"] = BRACKET_SIZE*2, ["C"] = 0.00050, ["D"] = -1 },
        ["Green"] = { ["A"] = 0, ["B"] = BRACKET_SIZE*2, ["C"] = 0.001, ["D"] = 1 },
        ["Description"] = "Uncommon"
    },
    [BRACKET_SIZE*2] = {
        ["Red"] = { ["A"] = 1, ["B"] = BRACKET_SIZE, ["C"] = 0.00088, ["D"] = -1 },
        ["Blue"] = { ["A"] = 1, ["B"] = 000, ["C"] = 0.00000, ["D"] = 0 },
        ["Green"] = { ["A"] = 1, ["B"] = BRACKET_SIZE, ["C"] = 0.001, ["D"] = -1 },
        ["Description"] = "Common"
    },
    [BRACKET_SIZE] = {
        ["Red"] = { ["A"] = 0.55, ["B"] = 0, ["C"] = 0.00045, ["D"] = 1 },
        ["Blue"] = { ["A"] = 0.55, ["B"] = 0, ["C"] = 0.00045, ["D"] = 1 },
        ["Green"] = { ["A"] = 0.55, ["B"] = 0, ["C"] = 0.00045, ["D"] = 1 },
        ["Description"] = "Trash"
    },
}

local function GetQuality(ItemScore)
    ItemScore = tonumber(ItemScore)
    if not ItemScore then
        return 0, 0, 0, "Trash"
    end
    if ItemScore > MAX_SCORE then
        ItemScore = MAX_SCORE
    end
    local Red = 0.1
    local Blue = 0.1
    local Green = 0.1
    local GS_QualityDescription = "Legendary"
    for i = 0, 6 do
        if (ItemScore > i * BRACKET_SIZE) and (ItemScore <= ((i + 1) * BRACKET_SIZE)) then
            local Red = GS_Quality[(i + 1) * BRACKET_SIZE].Red["A"] + (((ItemScore - GS_Quality[(i + 1) * BRACKET_SIZE].Red["B"]) * GS_Quality[(i + 1) * BRACKET_SIZE].Red["C"]) * GS_Quality[(i + 1) * BRACKET_SIZE].Red["D"])
            local Blue = GS_Quality[(i + 1) * BRACKET_SIZE].Green["A"] + (((ItemScore - GS_Quality[(i + 1) * BRACKET_SIZE].Green["B"]) * GS_Quality[(i + 1) * BRACKET_SIZE].Green["C"]) * GS_Quality[(i + 1) * BRACKET_SIZE].Green["D"])
            local Green = GS_Quality[(i + 1) * BRACKET_SIZE].Blue["A"] + (((ItemScore - GS_Quality[(i + 1) * BRACKET_SIZE].Blue["B"]) * GS_Quality[(i + 1) * BRACKET_SIZE].Blue["C"]) * GS_Quality[(i + 1) * BRACKET_SIZE].Blue["D"])
            return Red, Green, Blue, GS_Quality[(i + 1) * BRACKET_SIZE].Description
        end
    end
    return 0.1, 0.1, 0.1, "Trash"
end

local function GetItemScore(ItemLink)
    if not ItemLink then
        return 0, 0, 0.1, 0.1, 0.1
    end
    local ItemName, ItemLink, ItemRarity, ItemLevel, ItemMinLevel, ItemType, ItemSubType, ItemStackCount, ItemEquipLoc, ItemTexture = GetItemInfo(ItemLink)
    if ItemLink and ItemRarity and ItemLevel and ItemEquipLoc and GS_ItemTypes[ItemEquipLoc] then
        local Table
        local QualityScale = 1
        local GearScore = 0
        local Scale = 1.8618
        if ItemRarity == 5 then 
            QualityScale = 1.3
            ItemRarity = 4
        elseif ItemRarity == 1 then
            QualityScale = 0.005
            ItemRarity = 2
        elseif ItemRarity == 0 then
            QualityScale = 0.005
            ItemRarity = 2
        elseif ItemRarity == 7 then
            ItemRarity = 3
            ItemLevel = 187.05
        end
        if ItemLevel < 100 and ItemRarity == 4 then
            Table = GS_Formula["C"]
        elseif ItemLevel < 168 and ItemRarity == 4 then
            Table = GS_Formula["B"]
        elseif ItemLevel < 148 and ItemRarity == 3 then
            Table = GS_Formula["B"]
        elseif ItemLevel < 138 and ItemRarity == 2 then
            Table = GS_Formula["B"]
        elseif ItemLevel <= 120 then
            Table = GS_Formula["B"]
        else
            Table = GS_Formula["A"]
        end
        if (ItemRarity >= 2) and (ItemRarity <= 4) then
            local Red, Green, Blue = GetQuality((floor(((ItemLevel - Table[ItemRarity].A) / Table[ItemRarity].B) * 1 * Scale)) * 11.25)
            GearScore = floor(((ItemLevel - Table[ItemRarity].A) / Table[ItemRarity].B) * GS_ItemTypes[ItemEquipLoc].SlotMOD * Scale * QualityScale)
            if ItemLevel == 187.05 then
                ItemLevel = 0
            end
            if GearScore < 0 then
                GearScore = 0
                Red, Green, Blue = GetQuality(1)
            end
            return GearScore, ItemLevel, Red, Green, Blue, ItemEquipLoc
        end
    end
    return 0, 0, 0.1, 0.1, 0.1, 0
end

-- Helper: GetUnitGearInfo (The Core Logic)
local function GetUnitGearInfo(unit)
    local guid = UnitGUID(unit)
    local _, englishClass = UnitClass(unit)
    
    -- Check cache FIRST - this allows showing cached data for remote players
    if guid and gearCache[guid] and gearCache[guid].gs then
        local cache = gearCache[guid]
        return cache.gs, cache.ilvl, true, true
    end
    
    local GearScore = 0
    local ItemCount = 0
    local LevelTotal = 0
    local TitanGrip = 1
    local hasItemIDs = false
    
    local mainHandItem = GetInventoryItemLink(unit, 16)
    local offHandItem = GetInventoryItemLink(unit, 17)
    
    if mainHandItem and offHandItem then
        local _, _, _, _, _, _, _, _, equipLoc = GetItemInfo(mainHandItem)
        if equipLoc == "INVTYPE_2HWEAPON" then
            TitanGrip = 0.5
        end
    end
    
    if offHandItem then
        local _, _, _, _, _, _, _, _, equipLoc = GetItemInfo(offHandItem)
        if equipLoc == "INVTYPE_2HWEAPON" then
            TitanGrip = 0.5
        end
        local TempScore, ItemLevel = GetItemScore(offHandItem)
        if englishClass == "HUNTER" then
            TempScore = floor(TempScore * 0.3164)
        end
        GearScore = GearScore + TempScore * TitanGrip
        ItemCount = ItemCount + 1
        LevelTotal = LevelTotal + ItemLevel
        hasItemIDs = true
    end
    
    for i = 1, 18 do
        if (i ~= 4) and (i ~= 17) then
            local itemLink = GetInventoryItemLink(unit, i)
            if itemLink then
                hasItemIDs = true
                local TempScore, ItemLevel = GetItemScore(itemLink)
                if englishClass == "HUNTER" then
                    if i == 16 then
                        TempScore = floor(TempScore * 0.3164)
                    elseif i == 18 then
                        TempScore = floor(TempScore * 5.3224)
                    end
                end
                if i == 16 then
                    TempScore = TempScore * TitanGrip
                end
                GearScore = GearScore + TempScore
                ItemCount = ItemCount + 1
                LevelTotal = LevelTotal + ItemLevel
            end
        end
    end
    
    if ItemCount > 0 and GearScore > 0 then
        local finalGS = floor(GearScore)
        local averageItemLevel = floor(LevelTotal / ItemCount)
        
        if guid then
            if not gearCache[guid] then
                gearCache[guid] = {}
            end
            gearCache[guid].gs = finalGS
            gearCache[guid].ilvl = averageItemLevel
            gearCache[guid].time = GetTime()
        end
        
        return finalGS, averageItemLevel, false, hasItemIDs
    end
    
    return 0, 0, false, hasItemIDs
end

-- Event Handlers
function frame:INSPECT_READY(event, inspectGUID)
    if not inspectGUID then return end
    -- Only process if this matches our most recent inspection request
    if currentInspectGUID and inspectGUID ~= currentInspectGUID then return end
    
    local function AttemptTalentRead(attemptsLeft)
        if currentInspectGUID and inspectGUID ~= currentInspectGUID then return end -- Abort if target changed
        
        -- Try to find the unit for this GUID (needed for Retail GetInspectSpecialization)
        local unit = nil
        if UnitGUID("mouseover") == inspectGUID then unit = "mouseover"
        elseif UnitGUID("target") == inspectGUID then unit = "target"
        elseif UnitGUID("focus") == inspectGUID then unit = "focus"
        end

        -- In Classic, GetTabPoints(i, true) uses the last inspected unit internally, so unit arg is less strict,
        -- but for Retail we need a valid UnitID.
        
        if not unit and WOW_PROJECT_ID == WOW_PROJECT_MAINLINE then
             -- Can't read retail specs without a UnitID
             if attemptsLeft > 0 then
                 C_Timer.After(0.2, function() AttemptTalentRead(attemptsLeft - 1) end)
             end
             return
        end
        
        -- Use "mouseover" as fallback for Classic if unit not found (it usually works if inspect is active)
        if not unit then unit = "mouseover" end

        local talentString, validScan, totalPoints = GetUnitTalentString(unit, true)
        
        if validScan then
             -- If we have points or we are out of retries, save it.
             -- If 0 points and we have retries left, wait and retry.
             if totalPoints > 0 or attemptsLeft <= 0 then
                 if not gearCache[inspectGUID] then gearCache[inspectGUID] = {} end
                 gearCache[inspectGUID].talents = talentString
                 
                 -- Update tooltip
                 if GameTooltip:IsVisible() then
                    local unit = GetTooltipUnit(GameTooltip)
                    if unit then
                        local unitGUID = UnitGUID(unit)
                        if unitGUID and inspectGUID == unitGUID then
                             GameTooltip:SetUnit(unit)
                        end
                    end
                end
             else
                 -- Retry
                 C_Timer.After(0.2, function() AttemptTalentRead(attemptsLeft - 1) end)
             end
        else
             -- No valid tabs found? Retry if possible
             if attemptsLeft > 0 then
                 C_Timer.After(0.2, function() AttemptTalentRead(attemptsLeft - 1) end)
             else
                 -- Final attempt failed, but we might still have GS/iLvl
                 if GameTooltip:IsVisible() then
                     local unit = GetTooltipUnit(GameTooltip)
                     if unit then GameTooltip:SetUnit(unit) end
                 end
             end
        end
    end
    
    -- Start trying to read talents
    C_Timer.After(0.1, function() AttemptTalentRead(3) end)
end

function frame:GET_ITEM_INFO_RECEIVED(event, itemID, success)
    -- If we were waiting for item info, refresh tooltip
    if GameTooltip:IsVisible() then
         local unit = GetTooltipUnit(GameTooltip)
         if unit then GameTooltip:SetUnit(unit) end
    end
end

-- Tooltip Hook
GameTooltip:HookScript("OnTooltipSetUnit", function(self)
    local unit = GetTooltipUnit(self)
    if not unit then return end
    
    if UnitIsPlayer(unit) and CLASS_ICON_TCOORDS then
        local _, class = UnitClass(unit)
        local coords = class and CLASS_ICON_TCOORDS[class]
        if coords then
            local line = _G[self:GetName() .. "TextLeft1"]
            if line then
                local current = line:GetText() or ""
                if current ~= "" and not string.find(current, "UI-Classes-Circles", 1, true) then
                    local left, right, top, bottom = coords[1], coords[2], coords[3], coords[4]
                    local iconMarkup = string.format(
                        "|TInterface\\TargetingFrame\\UI-Classes-Circles:16:16:0:0:256:256:%d:%d:%d:%d|t ",
                        left * 256, right * 256, top * 256, bottom * 256
                    )
                    line:SetText(iconMarkup .. current)
                end
            end
        end
    end
    
    -- Auto Inspect for all players, but only if they are in visible range
    -- This avoids "Target is too far away" errors while still showing data for remote players (cached)
    if GearScoreDB.autoInspect and CanInspect(unit) then
        SmartInspect(unit)
    elseif IsShiftKeyDown() and CanInspect(unit) then
        SmartInspect(unit)
    end
    
    local guid = UnitGUID(unit)
    if not guid then return end
    
    local gs, ilvl, isCached, hasItemIDs = GetUnitGearInfo(unit)
    
    -- Always show if we have data (cached or fresh)
    -- Only hide if we have absolutely no data and no items
    if gs == 0 and ilvl == 0 and not hasItemIDs then
        return
    end
    
    local linesAdded = false
    
    if GearScoreDB.showGS then
        -- Get quality colors for the gear score (TacoTip style)
        local red, green, blue, qualityDesc = GetQuality(gs)
        local gsColor = string.format("|cff%02x%02x%02x", red * 255, green * 255, blue * 255)
        local msg = addon.L["GEARSCORE_LABEL"] .. " " .. gsColor .. gs .. "|r (" .. qualityDesc .. ")"
        if isCached then msg = msg .. " (*)" end
        self:AddLine(msg, 1, 0.82, 0)
        linesAdded = true
    end
    
    if GearScoreDB.showiLvl then
        local msg = addon.L["ILVL_LABEL"] .. " |cffffffff" .. ilvl .. "|r"
        self:AddLine(msg, 1, 0.82, 0)
        linesAdded = true
    end
    
    if GearScoreDB.showTalents then
        local talents = nil
        
        -- Try to get talents (local or cached)
        if UnitIsUnit(unit, "player") then
            talents = GetUnitTalentString(unit, false)
        else
            if gearCache[guid] and gearCache[guid].talents then
                talents = gearCache[guid].talents
            end
        end
        
        if talents then
            self:AddLine(addon.L["TALENTS_LABEL"] .. " |cffffffff" .. talents .. "|r", 1, 0.82, 0)
            linesAdded = true
        else
             -- If we are inspecting, it might come soon
        end
    end

    if UnitIsPlayer(unit) and UnitGroupRolesAssigned then
        local role = UnitGroupRolesAssigned(unit)
        if role and role ~= "NONE" then
            local icon = ""
            local coords = ROLE_ICON_TCOORDS[role]
            if coords then
                local left, right, top, bottom = coords[1], coords[2], coords[3], coords[4]
                icon = string.format(
                    "|TInterface\\LFGFrame\\UI-LFG-ICON-ROLES:14:14:0:0:256:256:%d:%d:%d:%d|t ",
                    left * 256, right * 256, top * 256, bottom * 256
                )
            end
            local text = ROLE_NAMES[role] or role
            self:AddLine(icon .. text, 1, 1, 1)
            linesAdded = true
        end
    end

    -- Language Display (Addon Comm)
    if UnitIsPlayer(unit) and not UnitIsUnit(unit, "player") then
        local name, realm = UnitName(unit)
        local lookupKey = name
        if realm then lookupKey = name .. "-" .. realm end
        
        -- Priority 1: Client Language (from Addon Comm) - The "Real" Language
        local lang = langCache[lookupKey]
        if not lang and realm then lang = langCache[name] end
        
        -- Priority 2: Realm Language (Fallback / Guess)
        local isRealmGuess = false
        if not lang then
            local targetRealm = realm
            if not targetRealm then targetRealm = GetRealmName() end
            
            if RealmData[targetRealm] then
                lang = RealmData[targetRealm]
                isRealmGuess = true
            end
        end
        
        if lang then
            local flag = GetLanguageFlag(lang)
            self:AddLine(addon.L["LANGUAGE_LABEL"] .. " " .. flag, 1, 1, 1)
            linesAdded = true
        else
            -- Show pending state [?]
            self:AddLine(addon.L["LANGUAGE_LABEL"] .. " " .. GetLanguageFlag(nil), 1, 1, 1)
            linesAdded = true

            -- Query if not known
            if UnitIsConnected(unit) and UnitIsPlayer(unit) then
                -- Check Faction (Can't whisper cross-faction)
                local faction = UnitFactionGroup(unit)
                local myFaction = UnitFactionGroup("player")
                
                if faction == myFaction then
                    local target = name
                    if realm then target = name .. "-" .. realm end
                    
                    -- Throttle queries (one per 5 seconds per player)
                    local now = GetTime()
                    if not queryCooldown[target] or (now - queryCooldown[target] > 5) then
                        queryCooldown[target] = now
                        if SendAddonMessage then
                             pendingQueries[target] = now -- Register for suppression
                             SendAddonMessage(COMM_PREFIX, "QUERY", "WHISPER", target)
                        end
                    end
                end
            end
        end
    elseif UnitIsUnit(unit, "player") then
         -- Show own language
         local myLang = GearScoreDB.language
         if not myLang or myLang == "Auto" then myLang = GetLocale() end
         local flag = GetLanguageFlag(myLang)
         self:AddLine(addon.L["LANGUAGE_LABEL"] .. " " .. flag, 1, 1, 1)
         linesAdded = true
    end
    
    if linesAdded then self:Show() end
end)

-- === Item Level Overlay ===

local function CreateItemLevelOverlay(button)
    if not button then return end
    if button.rlOverlay then return button.rlOverlay end
    
    local text = button:CreateFontString(nil, "OVERLAY")
    text:SetPoint("TOPLEFT", 2, -2)
    
    -- Improved contrast: Yellow with thick outline and shadow
    local fontPath = GameFontNormal:GetFont()
    text:SetFont(fontPath, 11, "OUTLINE") 
    text:SetTextColor(1, 1, 0) -- Yellow
    text:SetShadowOffset(1, -1)
    text:SetShadowColor(0, 0, 0, 1)
    
    button.rlOverlay = text
    return text
end

local function UpdateItemLevelOverlay(button, link)
    if not GearScoreDB.showOverlay then
        if button.rlOverlay then button.rlOverlay:SetText("") end
        return
    end
    
    if not link then
        if button.rlOverlay then button.rlOverlay:SetText("") end
        return
    end
    
    local _, _, _, itemLevel = GetItemInfo(link)
    if itemLevel and itemLevel > 1 then
        local text = CreateItemLevelOverlay(button)
        text:SetText(itemLevel)
    else
        if button.rlOverlay then button.rlOverlay:SetText("") end
    end
end

-- Hook Character Frame (Player)
if PaperDollItemSlotButton_Update then
    hooksecurefunc("PaperDollItemSlotButton_Update", function(self)
        if self:GetID() then
             local unit = "player"
             local itemLink = GetInventoryItemLink(unit, self:GetID())
             UpdateItemLevelOverlay(self, itemLink)
        end
    end)
end

-- Hook Bags (Classic & Retail)
local function HookBags()
    if ContainerFrame_Update then
        hooksecurefunc("ContainerFrame_Update", function(frame)
             local name = frame:GetName()
             for i = 1, frame.size do
                 local button = _G[name .. "Item" .. i]
                 if button then
                     local id = button:GetID()
                    local link
                    if C_Container and C_Container.GetContainerItemLink then
                        link = C_Container.GetContainerItemLink(frame:GetID(), id)
                    elseif GetContainerItemLink then
                        link = GetContainerItemLink(frame:GetID(), id)
                    end
                    UpdateItemLevelOverlay(button, link)
                 end
             end
        end)
    end
end
HookBags()

-- =========================================================================
-- VERSION CHECK (CurseForge notification)
-- =========================================================================
local function RLGearscore_ParseVersion(v)
    local parts = {strsplit(".", v)}
    local result = 0
    for i = 1, math.min(#parts, 4) do
        result = result * 100 + (tonumber(parts[i]) or 0)
    end
    return result
end

local RLGearscore_VersionCheckFrame = CreateFrame("Frame")
RLGearscore_VersionCheckFrame:RegisterEvent("PLAYER_LOGIN")
RLGearscore_VersionCheckFrame:RegisterEvent("CHAT_MSG_ADDON")
local RLGearscore_detectedNewer = false
local RLGearscore_version = (GetAddOnMetadata and GetAddOnMetadata("RLGearscore", "Version")) or "1.3"
RLGearscore_VersionCheckFrame:SetScript("OnEvent", function(self, event, ...)
    if event == "PLAYER_LOGIN" then
        C_ChatInfo.RegisterAddonMessagePrefix("RLGearscore")
        C_Timer.After(5, function()
            if IsInGuild() then
                C_ChatInfo.SendAddonMessage("RLGearscore", "Version:" .. RLGearscore_version, "GUILD")
            end
        end)
    elseif event == "CHAT_MSG_ADDON" then
        local prefix, msg, channel, sender = ...
        if prefix ~= "RLGearscore" or sender == UnitName("player") then return end
        local ver = string.match(msg, "Version:(.+)")
        if ver and not RLGearscore_detectedNewer then
            if RLGearscore_ParseVersion(ver) > RLGearscore_ParseVersion(RLGearscore_version) then
                RLGearscore_detectedNewer = true
                if GetLocale() == "deDE" then
                    print("|cffFFD700[RLGearscore]|r Eine |cffffd100neue Version|r ist auf |cff00ffffCurseForge|r verfügbar!")
                else
                    print("|cffFFD700[RLGearscore]|r A |cffffd100new version|r is available on |cff00ffffCurseForge|r!")
                end
            end
        end
    end
end)
