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" spam when sending Addon Messages
if ChatFrame_AddMessageEventFilter then
    ChatFrame_AddMessageEventFilter("CHAT_MSG_SYSTEM", function(self, event, msg)
        if not msg then return false end
        local now = GetTime()
        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

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
local optionsFrame
local settingsPanel, aboutPanel

local function CreateOptionsFrame()
    if optionsFrame then return end
    
    optionsFrame = CreateFrame("Frame", "RLGearscoreOptions", UIParent, "BackdropTemplate")
    optionsFrame:SetSize(300, 500)
    optionsFrame:SetPoint("CENTER")
    optionsFrame:SetBackdrop({
        bgFile = "Interface\\DialogFrame\\UI-DialogBox-Background",
        edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Border",
        tile = true, tileSize = 32, edgeSize = 32,
        insets = { left = 11, right = 12, top = 12, bottom = 11 }
    })
    optionsFrame:SetMovable(true)
    optionsFrame:EnableMouse(true)
    optionsFrame:RegisterForDrag("LeftButton")
    optionsFrame:SetScript("OnDragStart", optionsFrame.StartMoving)
    optionsFrame:SetScript("OnDragStop", optionsFrame.StopMovingOrSizing)
    optionsFrame:Hide()
    
    -- Title
    local title = optionsFrame:CreateFontString(nil, "ARTWORK", "GameFontNormalLarge")
    title:SetPoint("TOP", 0, -15)
    title:SetText(addon.L["OPTIONS_TITLE"])
    optionsFrame.title = title

    -- Tabs Container
    local tab1 = CreateFrame("Button", nil, optionsFrame, "UIPanelButtonTemplate")
    tab1:SetSize(100, 25)
    tab1:SetPoint("TOPLEFT", 20, -45)
    tab1:SetText(addon.L["TAB_SETTINGS"])
    optionsFrame.tab1 = tab1
    
    local tab2 = CreateFrame("Button", nil, optionsFrame, "UIPanelButtonTemplate")
    tab2:SetSize(100, 25)
    tab2:SetPoint("TOPRIGHT", -20, -45)
    tab2:SetText(addon.L["TAB_ABOUT"])
    optionsFrame.tab2 = tab2

    -- Panels
    settingsPanel = CreateFrame("Frame", nil, optionsFrame)
    settingsPanel:SetPoint("TOPLEFT", 0, -80)
    settingsPanel:SetPoint("BOTTOMRIGHT", 0, 40)
    
    aboutPanel = CreateFrame("Frame", nil, optionsFrame)
    aboutPanel:SetPoint("TOPLEFT", 0, -80)
    aboutPanel:SetPoint("BOTTOMRIGHT", 0, 40)
    aboutPanel:Hide()

    -- Tab Logic
    tab1:SetScript("OnClick", function()
        settingsPanel:Show()
        aboutPanel:Hide()
        tab1:Disable()
        tab2:Enable()
    end)
    
    tab2:SetScript("OnClick", function()
        settingsPanel:Hide()
        aboutPanel:Show()
        tab1:Enable()
        tab2:Disable()
    end)
    tab1:Disable() -- Default active

    -- === Settings Panel Content ===
    
    -- Checkboxes
    local function CreateCheckbox(key, labelText, relativeTo, yOffset)
        local cb = CreateFrame("CheckButton", nil, settingsPanel, "UICheckButtonTemplate")
        if relativeTo then
             cb:SetPoint("TOPLEFT", relativeTo, "BOTTOMLEFT", 0, yOffset)
        else
             cb:SetPoint("TOPLEFT", 20, yOffset)
        end
        cb.text = cb:CreateFontString(nil, "OVERLAY", "GameFontNormal")
        cb.text:SetPoint("LEFT", cb, "RIGHT", 5, 1)
        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
                optionsFrame.title:SetText(addon.L["OPTIONS_TITLE"])
                optionsFrame.tab1:SetText(addon.L["TAB_SETTINGS"])
                optionsFrame.tab2: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(260)
    copyText:SetJustifyH("CENTER")
    copyText:SetText(addon.L["ABOUT_CONTACT_INFO"])
    
    -- Git URL
    local gitEditBox = CreateFrame("EditBox", nil, aboutPanel, "InputBoxTemplate")
    gitEditBox:SetSize(250, 20)
    gitEditBox:SetPoint("TOP", copyText, "BOTTOM", 5, -10)
    gitEditBox:SetAutoFocus(false)
    gitEditBox:SetText("git clone https://xarmina.eu/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(260)
    creditsText:SetJustifyH("CENTER")
    creditsText:SetText(addon.L["CREDITS_TEXT"])
    aboutPanel.creditsText = creditsText
    
    -- Link
    local linkEditBox = CreateFrame("EditBox", nil, aboutPanel, "InputBoxTemplate")
    linkEditBox:SetSize(250, 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)
    
    -- Close Button
    local closeBtn = CreateFrame("Button", nil, optionsFrame, "UIPanelButtonTemplate")
    closeBtn:SetSize(80, 22)
    closeBtn:SetPoint("BOTTOM", 0, 15)
    closeBtn:SetText(CLOSE)
    closeBtn:SetScript("OnClick", function() optionsFrame:Hide() end)
end

-- Minimap Button
local minimapBtn
local function CreateMinimapButton()
    minimapBtn = CreateFrame("Button", "RLGearscoreMinimapButton", Minimap)
    minimapBtn:SetSize(32, 32)
    minimapBtn:SetFrameLevel(8)
    
    minimapBtn.icon = minimapBtn:CreateTexture(nil, "BACKGROUND")
    minimapBtn.icon:SetTexture("Interface\\AddOns\\RLGearscore\\img\\logo.png")
    minimapBtn.icon:SetSize(20, 20)
    minimapBtn.icon:SetPoint("CENTER")
    
    minimapBtn.border = minimapBtn:CreateTexture(nil, "OVERLAY")
    minimapBtn.border:SetTexture("Interface\\Minimap\\MiniMap-TrackingBorder")
    minimapBtn.border:SetSize(54, 54)
    minimapBtn.border:SetPoint("TOPLEFT")
    
    minimapBtn:RegisterForDrag("LeftButton")
    minimapBtn:SetHighlightTexture("Interface\\Minimap\\UI-Minimap-ZoomButton-Highlight")

    local function UpdatePosition()
        local angle = math.rad(GearScoreDB.minimapPos or 45)
        local x = math.cos(angle) * 80
        local y = math.sin(angle) * 80
        minimapBtn:SetPoint("CENTER", Minimap, "CENTER", x, y)
    end

    minimapBtn:SetScript("OnDragStart", function(self)
        self:LockHighlight()
        self:SetScript("OnUpdate", function(self)
            local mx, my = Minimap:GetCenter()
            local cx, cy = GetCursorPosition()
            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)
    end)

    minimapBtn:SetScript("OnDragStop", function(self)
        self:UnlockHighlight()
        self:SetScript("OnUpdate", nil)
    end)

    minimapBtn:SetScript("OnClick", function(self, button)
        if button == "LeftButton" then
            if not optionsFrame then CreateOptionsFrame() end
            if optionsFrame:IsShown() then optionsFrame:Hide() else optionsFrame:Show() end
        end
    end)

    minimapBtn: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)
    
    minimapBtn:SetScript("OnLeave", function() GameTooltip:Hide() 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

    local now = GetTime()
    if (now - lastInspectTime > 1.5) then
        lastInspectTime = now
        
        -- Suppress UI errors (red text) during inspect to avoid spam
        UIErrorsFrame:UnregisterEvent("UI_ERROR_MESSAGE")
        
        if ClearInspectPlayer then ClearInspectPlayer() end
        NotifyInspect(unit)
        currentInspectGUID = UnitGUID(unit)
        
        C_Timer.After(0.1, 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

-- Helper: GetUnitGearInfo (The Core Logic)
local gearCache = {}
local function GetUnitGearInfo(unit)
    local guid = UnitGUID(unit)
    local ignoreSlots = {
        [4] = true,
        [18] = true,
        [19] = true
    }
    local twoHandTypes = {
        INVTYPE_2HWEAPON = true,
        INVTYPE_RANGED = true,
        INVTYPE_RANGEDRIGHT = true
    }
    local slotMod = {
        INVTYPE_NECK = 0.5625,
        INVTYPE_SHOULDER = 0.75,
        INVTYPE_BODY = 0,
        INVTYPE_WAIST = 0.75,
        INVTYPE_FEET = 0.75,
        INVTYPE_WRIST = 0.5625,
        INVTYPE_HAND = 0.75,
        INVTYPE_FINGER = 0.5625,
        INVTYPE_TRINKET = 0.5625,
        INVTYPE_RANGED = 0.3164,
        INVTYPE_CLOAK = 0.5625,
        INVTYPE_THROWN = 0.3164,
        INVTYPE_RANGEDRIGHT = 0.3164,
        INVTYPE_RELIC = 0.3164
    }
    local totalScore = 0
    local totalItems = 0
    local totalQuality = 0
    local totalItemsForQuality = 0
    local gearScore = 0
    local hasItemIDs = false
    for slot = 1, 19 do
        local itemLink = GetInventoryItemLink(unit, slot)
        if itemLink then
            hasItemIDs = true
            local itemLevel
            if GetDetailedItemLevelInfo then
                itemLevel = GetDetailedItemLevelInfo(itemLink)
            end
            if not itemLevel or itemLevel <= 0 then
                local _, _, _, levelFallback = GetItemInfo(itemLink)
                itemLevel = levelFallback
            end
            local _, _, quality, _, _, _, _, _, equipLoc = GetItemInfo(itemLink)
            if itemLevel and itemLevel > 0 and not ignoreSlots[slot] then
                local q = quality or 0
                if q == 7 or q == 8 then
                    q = 3
                end
                local iLvlToAdd = itemLevel
                local twoHandedMainHandOnly = false
                totalItems = totalItems + 1
                if slot == 16 or slot == 17 then
                    local mainLink = GetInventoryItemLink(unit, 16)
                    local offLink = GetInventoryItemLink(unit, 17)
                    local isMainHandOnly = mainLink and not offLink
                    if isMainHandOnly and equipLoc and twoHandTypes[equipLoc] then
                        iLvlToAdd = itemLevel * 2
                        totalItems = totalItems + 1
                        twoHandedMainHandOnly = true
                    end
                end
                totalScore = totalScore + iLvlToAdd
                totalItemsForQuality = totalItemsForQuality + 1
                totalQuality = totalQuality + q
                local qualityMod = ((q == 0 or q == 1) and 0.005) or (q == 5 and 1.3) or (q == 6 and 1.69) or 1
                local sMod = slotMod[equipLoc] or 1
                gearScore = gearScore + iLvlToAdd * sMod * qualityMod
            end
        end
    end
    if totalItemsForQuality == 0 then
        if guid and gearCache[guid] and gearCache[guid].gs then
            local cache = gearCache[guid]
            return cache.gs, cache.ilvl, true, hasItemIDs
        end
        return 0, 0, false, hasItemIDs
    end
    local averageItemLevel
    local isSelf = UnitIsUnit(unit, "player")
    if isSelf and GetAverageItemLevel then
        local _, equipped, _ = GetAverageItemLevel()
        if equipped and equipped > 0 then
            averageItemLevel = math.floor(equipped)
        end
    elseif C_PaperDollInfo and C_PaperDollInfo.GetInspectItemLevel then
        averageItemLevel = C_PaperDollInfo.GetInspectItemLevel(unit)
    end
    if not averageItemLevel or averageItemLevel == 0 then
        averageItemLevel = math.floor(totalScore / 16)
    end
    local finalGS = math.floor(gearScore)
    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

-- 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 Trigger
    if CanInspect(unit) then
        SmartInspect(unit)
    end
    
    local guid = UnitGUID(unit)
    if not guid then return end
    
    local gs, ilvl, isCached, hasItemIDs = GetUnitGearInfo(unit)
    
    -- If we have no itemIDs (distance too far?), don't show 0
    if not hasItemIDs and gs == 0 then return end
    
    local linesAdded = false
    
    if GearScoreDB.showGS then
        local msg = addon.L["GEARSCORE_LABEL"] .. " |cffffffff" .. gs .. "|r"
        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()
