local addonName = ...

local db
local minimapButton
local optionsFrame

local clientLocale = GetLocale and GetLocale() or "enUS"

local Locales = {
    de = {
        TITLE = "RL Gearscore/Item Level",
        OPTIONS_HEADER = "Anzeigen:",
        OPTIONS_ENABLE = "Addon aktivieren",
        OPTIONS_GUILD = "Gilde anzeigen",
        OPTIONS_GUILDRANK = "Gildenrang anzeigen",
        OPTIONS_LEVEL = "Level/Rasse/Klasse anzeigen",
        OPTIONS_ILVL = "Itemlevel anzeigen",
        OPTIONS_GS = "Gearscore anzeigen",
        OPTIONS_TALENTS = "Talente 0/0/0 anzeigen",
        OPTIONS_QUEST = "Questinfos für Gegner anzeigen",
        OPTIONS_TAB_SETTINGS = "Einstellungen",
        OPTIONS_TAB_ABOUT = "Über",
        OPTIONS_TAB_LANGUAGE = "Sprache",
        OPTIONS_AUTOSAVE_HINT = "Änderungen werden automatisch gespeichert.",
        LANGUAGE_LABEL = "Sprache",
        LANG_AUTO = "Automatisch (Client-Sprache)",
        LANG_GERMAN = "Deutsch",
        LANG_ENGLISH = "Englisch",
        MINIMAP_TOOLTIP_TITLE = "RL Gearscore/Item Level",
        MINIMAP_TOOLTIP_LEFT = "Linksklick: Einstellungen",
        MINIMAP_TOOLTIP_RIGHT = "Rechtsklick: Addon an/aus",
        HEADER_TEXT = "RL Gearscore / Item Level",
        LABEL_ILVL_SHORT = "iLvl:",
        LABEL_ILVL_AVG = "iLvl Ø:",
        LABEL_GS = "GS:",
        LABEL_GS_TOTAL = "GS gesamt:",
        LABEL_TALENTS = "Talente:",
        LABEL_TARGETING = "Ziel:",
        CHAT_NO_TARGET = "RL Gearscore: Kein gültiges Ziel.",
        CHAT_PREFIX = "RL Gearscore:",
        CHAT_LEVEL_PATTERN = "Level %d %s %s",
        CHAT_TALENTS = "Talente: %s",
        ABOUT_HEADER = "Über RL Gearscore",
        ABOUT_TEXT = "Copyright © Robin Oliver Lucas\nSchwarzbach 148\n42277 Wuppertal\nDeutschland\n\nE-Mail: robin@rl-dev.de\nSpenden (PayPal): robin@rl-dev.de",
    },
    en = {
        TITLE = "RL Gearscore/Item Level",
        OPTIONS_HEADER = "Display:",
        OPTIONS_ENABLE = "Enable addon",
        OPTIONS_GUILD = "Show guild",
        OPTIONS_GUILDRANK = "Show guild rank",
        OPTIONS_LEVEL = "Show level/race/class",
        OPTIONS_ILVL = "Show item level",
        OPTIONS_GS = "Show gearscore",
        OPTIONS_TALENTS = "Show talents 0/0/0",
        OPTIONS_QUEST = "Show quest info for enemies",
        OPTIONS_TAB_SETTINGS = "Settings",
        OPTIONS_TAB_ABOUT = "About",
        OPTIONS_TAB_LANGUAGE = "Language",
        OPTIONS_AUTOSAVE_HINT = "Changes are saved automatically.",
        LANGUAGE_LABEL = "Language",
        LANG_AUTO = "Automatic (client language)",
        LANG_GERMAN = "German",
        LANG_ENGLISH = "English",
        MINIMAP_TOOLTIP_TITLE = "RL Gearscore/Item Level",
        MINIMAP_TOOLTIP_LEFT = "Left-click: Settings",
        MINIMAP_TOOLTIP_RIGHT = "Right-click: Toggle addon",
        HEADER_TEXT = "RL Gearscore / Item Level",
        LABEL_ILVL_SHORT = "iLvl:",
        LABEL_ILVL_AVG = "iLvl Ø:",
        LABEL_GS = "GS:",
        LABEL_GS_TOTAL = "GS total:",
        LABEL_TALENTS = "Talents:",
        LABEL_TARGETING = "Target:",
        CHAT_NO_TARGET = "RL Gearscore: No valid target.",
        CHAT_PREFIX = "RL Gearscore:",
        CHAT_LEVEL_PATTERN = "Level %d %s %s",
        CHAT_TALENTS = "Talents: %s",
        ABOUT_HEADER = "About RL Gearscore",
        ABOUT_TEXT = "Copyright © Robin Oliver Lucas\nSchwarzbach 148\n42277 Wuppertal\nGermany\n\nE-mail: robin@rl-dev.de\nDonations (PayPal): robin@rl-dev.de",
    },
}

local function getLanguage()
    local mode = "auto"
    if db and db.language then
        mode = db.language
    end
    if mode == "de" then
        return "de"
    elseif mode == "en" then
        return "en"
    end
    if clientLocale == "deDE" then
        return "de"
    end
    return "en"
end

local function L(key)
    local lang = getLanguage()
    local tbl = Locales[lang] or Locales.en
    return tbl[key] or key
end

local function ensureDB()
    if type(RLGearscoreDB) ~= "table" then
        RLGearscoreDB = {}
    end
    db = RLGearscoreDB
    if not db.language then
        db.language = "auto"
    end
    if db.enabled == nil then
        db.enabled = true
    end
    db.minimap = db.minimap or {}
    if not db.minimap.point then
        db.minimap.point = "TOPLEFT"
        db.minimap.relPoint = "TOPLEFT"
        db.minimap.x = 0
        db.minimap.y = 0
    end
    if db.showGuild == nil then
        db.showGuild = true
    end
    if db.showGuildRank == nil then
        db.showGuildRank = true
    end
    if db.showLevel == nil then
        db.showLevel = true
    end
    if db.showItemLevel == nil then
        db.showItemLevel = true
    end
    if db.showGearscore == nil then
        db.showGearscore = true
    end
    if db.showTalents == nil then
        db.showTalents = true
    end
    if db.showQuestInfo == nil then
        db.showQuestInfo = true
    end
end

local function getItemLevelAndScore(link)
    if not link or not IsEquippableItem(link) then
        return
    end
    local name, _, quality, level, _, _, _, _, equipLoc = GetItemInfo(link)
    if not name or not level or level <= 1 or not equipLoc or equipLoc == "" then
        return
    end
    local slotWeights = {
        INVTYPE_HEAD = 1.0,
        INVTYPE_NECK = 0.56,
        INVTYPE_SHOULDER = 0.75,
        INVTYPE_BODY = 0.0,
        INVTYPE_CHEST = 1.0,
        INVTYPE_ROBE = 1.0,
        INVTYPE_WAIST = 0.75,
        INVTYPE_LEGS = 1.0,
        INVTYPE_FEET = 0.75,
        INVTYPE_WRIST = 0.56,
        INVTYPE_HAND = 0.75,
        INVTYPE_FINGER = 0.56,
        INVTYPE_TRINKET = 0.56,
        INVTYPE_CLOAK = 0.56,
        INVTYPE_WEAPON = 1.0,
        INVTYPE_WEAPONMAINHAND = 1.0,
        INVTYPE_WEAPONOFFHAND = 1.0,
        INVTYPE_2HWEAPON = 2.0,
        INVTYPE_SHIELD = 1.0,
        INVTYPE_HOLDABLE = 1.0,
        INVTYPE_RANGED = 0.32,
        INVTYPE_RANGEDRIGHT = 0.32,
        INVTYPE_THROWN = 0.32,
        INVTYPE_RELIC = 0.32,
        INVTYPE_TABARD = 0.0,
    }
    local weight = slotWeights[equipLoc]
    if not weight or weight <= 0 then
        return level
    end
    local qualityScale = 1.0
    if quality == 0 then
        qualityScale = 0.5
    elseif quality == 1 then
        qualityScale = 0.75
    elseif quality == 2 then
        qualityScale = 1.0
    elseif quality == 3 then
        qualityScale = 1.1
    elseif quality == 4 then
        qualityScale = 1.25
    elseif quality >= 5 then
        qualityScale = 1.4
    end
    local score = math.floor(level * weight * qualityScale)
    return level, score
end

local function getDifficultyColorHex(ratio)
    if not ratio or ratio <= 0 then
        return "FFFFFFFF"
    end
    local r, g, b
    if ratio <= 0.8 then
        r, g, b = 0.0, 1.0, 0.0
    elseif ratio <= 1.0 then
        r, g, b = 1.0, 1.0, 0.0
    elseif ratio <= 1.2 then
        r, g, b = 1.0, 0.65, 0.0
    else
        r, g, b = 1.0, 0.0, 0.0
    end
    local ri = math.floor(r * 255 + 0.5)
    local gi = math.floor(g * 255 + 0.5)
    local bi = math.floor(b * 255 + 0.5)
    return string.format("FF%02X%02X%02X", ri, gi, bi)
end

local function colorByDifficulty(value, unitAvg, playerAvg)
    if not value then
        return ""
    end
    if not unitAvg or not playerAvg or playerAvg <= 0 then
        return tostring(value)
    end
    local ratio = unitAvg / playerAvg
    local hex = getDifficultyColorHex(ratio)
    return "|c" .. hex .. tostring(value) .. "|r"
end

local function styleUnitText(self, unit)
    if not self or not unit or not UnitExists(unit) or not self.GetName then
        return
    end
    local tipName = self:GetName()
    if not tipName then
        return
    end
    local name, realm = UnitName(unit)
    if not name then
        return
    end
    local level = UnitLevel(unit)
    local race = UnitRace(unit) or ""
    local classLoc, class = UnitClass(unit)
    local guildName, guildRank = GetGuildInfo(unit)
    local classColor = RAID_CLASS_COLORS and class and RAID_CLASS_COLORS[class]
    local levelColor = GetQuestDifficultyColor and GetQuestDifficultyColor(level) or { r = 1, g = 1, b = 1 }

    local line1 = _G[tipName .. "TextLeft1"]
    local line2 = _G[tipName .. "TextLeft2"]
    local line3 = _G[tipName .. "TextLeft3"]

    if line1 then
        local displayName = name
        if realm and realm ~= "" then
            displayName = name .. "-" .. realm
        end
        line1:SetText(displayName)
        if classColor then
            line1:SetTextColor(classColor.r, classColor.g, classColor.b)
        else
            line1:SetTextColor(1, 0.82, 0)
        end
    end

    if line2 and guildName then
        if not db then
            ensureDB()
        end
        if db and not db.showGuild then
            line2:SetText("")
            return
        end
        local txt
        if db and db.showGuildRank and guildRank and guildRank ~= "" then
            txt = "<" .. guildName .. "> " .. guildRank
        else
            txt = "<" .. guildName .. ">"
        end
        line2:SetText(txt)
        line2:SetTextColor(1.0, 0.4, 1.0)
    end

    if line3 and level and level > 0 then
        if not db then
            ensureDB()
        end
        if db and not db.showLevel then
            return
        end
        local txt = tostring(level)
        if race ~= "" then
            txt = txt .. " " .. race
        end
        if classLoc then
            txt = txt .. " " .. classLoc
        end
        line3:SetText(txt)
        line3:SetTextColor(levelColor.r or 1, levelColor.g or 1, levelColor.b or 1)
    end
end

local function brightenFonts(self)
    if not self or not self.GetName or not self.NumLines then
        return
    end
    local name = self:GetName()
    if not name then
        return
    end
    local numLines = self:NumLines() or 0
    for i = 1, numLines do
        local left = _G[name .. "TextLeft" .. i]
        if left and left.GetTextColor then
            local r, g, b = left:GetTextColor()
            local maxc = math.max(r or 0, g or 0, b or 0)
            if maxc < 0.8 then
                if maxc <= 0 then
                    r, g, b = 0.8, 0.8, 0.8
                else
                    local scale = 0.8 / maxc
                    r, g, b = math.min(r * scale, 1), math.min(g * scale, 1), math.min(b * scale, 1)
                end
                left:SetTextColor(r, g, b)
            end
        end
        local right = _G[name .. "TextRight" .. i]
        if right and right.GetTextColor then
            local r, g, b = right:GetTextColor()
            local maxc = math.max(r or 0, g or 0, b or 0)
            if maxc < 0.8 then
                if maxc <= 0 then
                    r, g, b = 0.8, 0.8, 0.8
                else
                    local scale = 0.8 / maxc
                    r, g, b = math.min(r * scale, 1), math.min(g * scale, 1), math.min(b * scale, 1)
                end
                right:SetTextColor(r, g, b)
            end
        end
    end
end

local function brightenTooltip(self, unit)
    if self.SetAlpha then
        self:SetAlpha(1)
    end
    if self.SetBackdrop and not self.__RLGearscoreStyled then
        self:SetBackdrop({
            bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
            edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
            tile = true,
            tileSize = 16,
            edgeSize = 16,
            insets = { left = 4, right = 4, top = 4, bottom = 4 },
        })
        self.__RLGearscoreStyled = true
    end
    if self.SetBackdropColor then
        self:SetBackdropColor(0, 0, 0, 1)
    end
    if self.SetBackdropBorderColor then
        local r, g, b = 0.6, 0.6, 0.6
        if unit and UnitIsPlayer(unit) and RAID_CLASS_COLORS then
            local _, class = UnitClass(unit)
            local c = class and RAID_CLASS_COLORS[class]
            if c then
                r, g, b = c.r, c.g, c.b
            end
        end
        self:SetBackdropBorderColor(r, g, b, 1)
    end
    brightenFonts(self)
end

local function getUnitAverageAndScore(unit)
    if not unit or not UnitIsPlayer(unit) then
        return
    end
    local slots = {
        1, 2, 3, 5, 6, 7, 8, 9, 10,
        11, 12, 13, 14, 15, 16, 17, 18,
    }
    local totalLevel = 0
    local totalScore = 0
    local count = 0
    for _, slot in ipairs(slots) do
        local link = GetInventoryItemLink(unit, slot)
        if link then
            local level, score = getItemLevelAndScore(link)
            if level then
                totalLevel = totalLevel + level
                count = count + 1
            end
            if score and score > 0 then
                totalScore = totalScore + score
            end
        end
    end
    if count == 0 then
        return
    end
    local avgLevel = totalLevel / count
    return avgLevel, totalScore
end

local function getTalentStringForUnit(unit, isInspect)
    if unit ~= "player" then
        if not isInspect then
            return
        end
    end
    if not GetNumTalentTabs or not GetTalentTabInfo then
        return
    end
    local numTabs = GetNumTalentTabs(isInspect and true or nil)
    if not numTabs or numTabs <= 0 then
        return
    end
    local p1, p2, p3 = 0, 0, 0
    if numTabs >= 1 then
        local _, _, _, _, spent = GetTalentTabInfo(1, isInspect and true or nil)
        p1 = spent or 0
    end
    if numTabs >= 2 then
        local _, _, _, _, spent = GetTalentTabInfo(2, isInspect and true or nil)
        p2 = spent or 0
    end
    if numTabs >= 3 then
        local _, _, _, _, spent = GetTalentTabInfo(3, isInspect and true or nil)
        p3 = spent or 0
    end
    return string.format("%d/%d/%d", p1, p2, p3)
end

local inspectCache = {}
local lastInspectTime = 0

local function findUnitByGUID(guid)
    if not guid then
        return
    end
    if UnitGUID("target") == guid then
        return "target"
    end
    if UnitGUID("mouseover") == guid then
        return "mouseover"
    end
    for i = 1, 4 do
        local u = "party" .. i
        if UnitGUID(u) == guid then
            return u
        end
    end
    for i = 1, 40 do
        local u = "raid" .. i
        if UnitGUID(u) == guid then
            return u
        end
    end
end

local function requestInspect(unit)
    if not unit or not UnitIsPlayer(unit) or UnitIsUnit(unit, "player") then
        return
    end
    if not CanInspect or not NotifyInspect then
        return
    end
    if not CanInspect(unit) then
        return
    end
    if InspectFrame and InspectFrame:IsShown() then
        return
    end
    local guid = UnitGUID(unit)
    if not guid then
        return
    end
    local now = GetTime and GetTime() or 0
    local cached = inspectCache[guid]
    if cached and cached.time and now - cached.time < 60 then
        return
    end
    if lastInspectTime > 0 and now - lastInspectTime < 2 then
        return
    end
    lastInspectTime = now
    NotifyInspect(unit)
end

local function getAverageAndScoreForUnit(unit)
    if not unit or not UnitIsPlayer(unit) then
        return
    end
    if UnitIsUnit(unit, "player") then
        local avg, total = getUnitAverageAndScore("player")
        local talents = getTalentStringForUnit("player", false)
        return avg, total, talents
    end
    local guid = UnitGUID(unit)
    if not guid then
        return
    end
    local entry = inspectCache[guid]
    if entry then
        return entry.avgLevel, entry.totalScore, entry.talentText
    end
    requestInspect(unit)
end

local function handleInspectReady(guid)
    if not guid then
        return
    end
    local unit = findUnitByGUID(guid)
    if not unit or not UnitIsPlayer(unit) then
        return
    end
    local avgLevel, totalScore = getUnitAverageAndScore(unit)
    if not avgLevel and not totalScore then
        return
    end
    local talentText = getTalentStringForUnit(unit, true)
    inspectCache[guid] = {
        avgLevel = avgLevel,
        totalScore = totalScore,
        talentText = talentText,
        time = GetTime and GetTime() or 0,
    }
    if GameTooltip and GameTooltip:IsShown() then
        local _, tipUnit = GameTooltip:GetUnit()
        if tipUnit and UnitGUID(tipUnit) == guid then
            GameTooltip:SetUnit(tipUnit)
        end
    end
end

local function ensureHeader(self)
    if self.__RLGearscoreHeaderDone then
        return
    end
    self:AddLine(" ")
    self:AddLine("|cFF00FFFF" .. L("HEADER_TEXT") .. "|r", 1.0, 1.0, 1.0)
    self.__RLGearscoreHeaderDone = true
end

local function addItemInfo(self)
    if not self or not self.GetItem then
        return
    end
    if not db then
        ensureDB()
    end
    if self.__RLGearscoreItemDone then
        return
    end
    self.__RLGearscoreItemDone = true
    if db and not db.enabled then
        return
    end
    local _, link = self:GetItem()
    if not link then
        return
    end
    local level, score = getItemLevelAndScore(link)
    if not level then
        return
    end
    brightenTooltip(self)
    if not db or db.showItemLevel then
        ensureHeader(self)
        self:AddLine("|cFF00FFFF" .. L("LABEL_ILVL_SHORT") .. "|r " .. level, 1.0, 1.0, 1.0)
    end
    if score and score > 0 and (not db or db.showGearscore) then
        ensureHeader(self)
        self:AddLine("|cFF00FFFF" .. L("LABEL_GS") .. "|r " .. score, 1.0, 1.0, 1.0)
    end
end

local function addUnitInfo(self)
    if not self or not self.GetUnit then
        return
    end
    if not db then
        ensureDB()
    end
    if db and not db.enabled then
        return
    end
    if self.__RLGearscoreUnitDone then
        return
    end
    local _, unit = self:GetUnit()
    if not unit then
        brightenTooltip(self)
        return
    end
    self.__RLGearscoreUnitDone = true
    if UnitIsPlayer(unit) then
        styleUnitText(self, unit)
        local avgLevel, totalScore, talentText = getAverageAndScoreForUnit(unit)
        local playerAvg, playerScore = getUnitAverageAndScore("player")
        brightenTooltip(self, unit)
        if avgLevel and (not db or db.showItemLevel) then
            ensureHeader(self)
            local colored = colorByDifficulty(string.format("%.1f", avgLevel), avgLevel, playerAvg)
            self:AddLine("|cFF00FFFF" .. L("LABEL_ILVL_AVG") .. "|r " .. colored, 1.0, 1.0, 1.0)
        end
        if totalScore and totalScore > 0 and (not db or db.showGearscore) then
            ensureHeader(self)
            local coloredScore = colorByDifficulty(totalScore, totalScore, playerScore)
            self:AddLine("|cFF00FFFF" .. L("LABEL_GS_TOTAL") .. "|r " .. coloredScore, 1.0, 1.0, 1.0)
        end
        if db and db.showTalents and talentText and talentText ~= "" then
            ensureHeader(self)
            self:AddLine("|cFF00FFFF" .. L("LABEL_TALENTS") .. "|r " .. talentText, 1.0, 1.0, 1.0)
        end
    else
        brightenTooltip(self, unit)
    end
    local target = unit .. "target"
    if UnitExists(target) then
        local tName = UnitName(target)
        if tName and tName ~= "" then
            local r, g, b = 1, 1, 1
            if UnitIsPlayer(target) and RAID_CLASS_COLORS then
                local _, tClass = UnitClass(target)
                local c = tClass and RAID_CLASS_COLORS[tClass]
                if c then
                    r, g, b = c.r, c.g, c.b
                end
            elseif UnitReaction(target, "player") then
                local reaction = UnitReaction(target, "player")
                if reaction == 4 then
                    r, g, b = 1, 1, 0
                elseif reaction > 4 then
                    r, g, b = 0, 1, 0
                else
                    r, g, b = 1, 0, 0
                end
            end
            ensureHeader(self)
            self:AddLine(L("LABEL_TARGETING") .. " [" .. tName .. "]", r, g, b)
        end
    end
end
 
local function onTooltipHide(self)
    self.__RLGearscoreItemDone = nil
    self.__RLGearscoreUnitDone = nil
    self.__RLGearscoreHeaderDone = nil
end

local function createOptionsFrame()
    if optionsFrame then
        return
    end
    if not db then
        ensureDB()
    end
    local f = CreateFrame("Frame", "RLGearscoreOptionsFrame", UIParent, "BasicFrameTemplateWithInset")
    optionsFrame = f
    f:SetSize(380, 440)
    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)
    f:Hide()
    local logoPath = "Interface\\AddOns\\rlgearscore\\img\\logo.png"
    local titleLogo = f:CreateTexture(nil, "ARTWORK")
    titleLogo:SetPoint("CENTER", f.TitleBg, "LEFT", 14, 0)
    titleLogo:SetSize(16, 16)
    titleLogo:SetTexture(logoPath)
    f.title = f:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    f.title:SetPoint("LEFT", titleLogo, "RIGHT", 6, 0)
    f.title:SetText(L("TITLE"))
    local tabSettings = CreateFrame("Button", nil, f, "UIPanelButtonTemplate")
    tabSettings:SetSize(100, 22)
    tabSettings:SetPoint("TOPLEFT", f, "TOPLEFT", 16, -54)
    tabSettings:SetText(L("OPTIONS_TAB_SETTINGS"))
    local tabLanguage = CreateFrame("Button", nil, f, "UIPanelButtonTemplate")
    tabLanguage:SetSize(100, 22)
    tabLanguage:SetPoint("LEFT", tabSettings, "RIGHT", 4, 0)
    tabLanguage:SetText(L("OPTIONS_TAB_LANGUAGE"))
    local tabAbout = CreateFrame("Button", nil, f, "UIPanelButtonTemplate")
    tabAbout:SetSize(80, 22)
    tabAbout:SetPoint("LEFT", tabLanguage, "RIGHT", 4, 0)
    tabAbout:SetText(L("OPTIONS_TAB_ABOUT"))
    local settingsPage = CreateFrame("Frame", nil, f)
    settingsPage:SetPoint("TOPLEFT", f, "TOPLEFT", 8, -84)
    settingsPage:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", -8, 8)
    local languagePage = CreateFrame("Frame", nil, f)
    languagePage:SetPoint("TOPLEFT", f, "TOPLEFT", 8, -84)
    languagePage:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", -8, 8)
    local aboutPage = CreateFrame("Frame", nil, f)
    aboutPage:SetPoint("TOPLEFT", f, "TOPLEFT", 8, -84)
    aboutPage:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", -8, 8)
    local header = settingsPage:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
    header:SetPoint("TOPLEFT", settingsPage, "TOPLEFT", 16, -10)
    header:SetText(L("OPTIONS_HEADER"))
    local checkboxes = {}
    local function createCheckbox(anchor, offsetY, label, key)
        local cb = CreateFrame("CheckButton", nil, settingsPage, "UICheckButtonTemplate")
        cb:SetPoint("TOPLEFT", anchor, "BOTTOMLEFT", 0, offsetY)
        local text = settingsPage:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
        text:SetPoint("LEFT", cb, "RIGHT", 4, 0)
        text:SetText(label)
        cb.text = text
        cb.dbKey = key
        table.insert(checkboxes, cb)
        cb:SetScript("OnClick", function(self)
            if not db then
                ensureDB()
            end
            if db then
                db[self.dbKey] = self:GetChecked() and true or false
            end
        end)
        return cb
    end
    local startAnchor = header
    local cbEnabled = createCheckbox(startAnchor, -10, L("OPTIONS_ENABLE"), "enabled")
    local cbGuild = createCheckbox(cbEnabled, -4, L("OPTIONS_GUILD"), "showGuild")
    local cbGuildRank = createCheckbox(cbGuild, -4, L("OPTIONS_GUILDRANK"), "showGuildRank")
    local cbLevel = createCheckbox(cbGuildRank, -4, L("OPTIONS_LEVEL"), "showLevel")
    local cbItemLevel = createCheckbox(cbLevel, -4, L("OPTIONS_ILVL"), "showItemLevel")
    local cbGearscore = createCheckbox(cbItemLevel, -4, L("OPTIONS_GS"), "showGearscore")
    local cbTalents = createCheckbox(cbGearscore, -4, L("OPTIONS_TALENTS"), "showTalents")
    local cbQuest = createCheckbox(cbTalents, -4, L("OPTIONS_QUEST"), "showQuestInfo")
    local autoSaveInfo = settingsPage:CreateFontString(nil, "OVERLAY", "GameFontDisableSmall")
    autoSaveInfo:SetPoint("TOPLEFT", cbQuest, "BOTTOMLEFT", 24, -8)
    autoSaveInfo:SetText(L("OPTIONS_AUTOSAVE_HINT") or "")
    local langLabel = languagePage:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    langLabel:SetPoint("TOPLEFT", languagePage, "TOPLEFT", 16, -16)
    langLabel:SetText(L("LANGUAGE_LABEL"))
    local langAuto = CreateFrame("CheckButton", nil, languagePage, "UIRadioButtonTemplate")
    langAuto:SetPoint("TOPLEFT", langLabel, "BOTTOMLEFT", 0, -4)
    langAuto.text:SetText(L("LANG_AUTO"))
    local langDe = CreateFrame("CheckButton", nil, languagePage, "UIRadioButtonTemplate")
    langDe:SetPoint("TOPLEFT", langAuto, "BOTTOMLEFT", 0, 0)
    langDe.text:SetText(L("LANG_GERMAN"))
    local langEn = CreateFrame("CheckButton", nil, languagePage, "UIRadioButtonTemplate")
    langEn:SetPoint("TOPLEFT", langDe, "BOTTOMLEFT", 0, 0)
    langEn.text:SetText(L("LANG_ENGLISH"))
    local refreshOptionsTexts
    langAuto:SetScript("OnClick", function()
        if not db then
            ensureDB()
        end
        db.language = "auto"
        langAuto:SetChecked(true)
        langDe:SetChecked(false)
        langEn:SetChecked(false)
        if refreshOptionsTexts then
            refreshOptionsTexts()
        end
    end)
    langDe:SetScript("OnClick", function()
        if not db then
            ensureDB()
        end
        db.language = "de"
        langAuto:SetChecked(false)
        langDe:SetChecked(true)
        langEn:SetChecked(false)
        if refreshOptionsTexts then
            refreshOptionsTexts()
        end
    end)
    langEn:SetScript("OnClick", function()
        if not db then
            ensureDB()
        end
        db.language = "en"
        langAuto:SetChecked(false)
        langDe:SetChecked(false)
        langEn:SetChecked(true)
        if refreshOptionsTexts then
            refreshOptionsTexts()
        end
    end)
    local aboutLogo = aboutPage:CreateTexture(nil, "ARTWORK")
    aboutLogo:SetPoint("TOPLEFT", aboutPage, "TOPLEFT", 8, -8)
    aboutLogo:SetSize(64, 64)
    aboutLogo:SetTexture(logoPath)
    local aboutTitle = aboutPage:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    aboutTitle:SetPoint("LEFT", aboutLogo, "RIGHT", 10, 0)
    aboutTitle:SetText(L("TITLE"))
    local aboutText = aboutPage:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    aboutText:SetPoint("TOPLEFT", aboutTitle, "BOTTOMLEFT", 0, -8)
    aboutText:SetWidth(320)
    aboutText:SetJustifyH("LEFT")
    aboutText:SetText(L("ABOUT_TEXT"))
    refreshOptionsTexts = function()
        f.title:SetText(L("TITLE"))
        tabSettings:SetText(L("OPTIONS_TAB_SETTINGS"))
        tabLanguage:SetText(L("OPTIONS_TAB_LANGUAGE"))
        tabAbout:SetText(L("OPTIONS_TAB_ABOUT"))
        header:SetText(L("OPTIONS_HEADER"))
        cbEnabled.text:SetText(L("OPTIONS_ENABLE"))
        cbGuild.text:SetText(L("OPTIONS_GUILD"))
        cbGuildRank.text:SetText(L("OPTIONS_GUILDRANK"))
        cbLevel.text:SetText(L("OPTIONS_LEVEL"))
        cbItemLevel.text:SetText(L("OPTIONS_ILVL"))
        cbGearscore.text:SetText(L("OPTIONS_GS"))
        cbTalents.text:SetText(L("OPTIONS_TALENTS"))
        cbQuest.text:SetText(L("OPTIONS_QUEST"))
        autoSaveInfo:SetText(L("OPTIONS_AUTOSAVE_HINT") or "")
        langLabel:SetText(L("LANGUAGE_LABEL"))
        langAuto.text:SetText(L("LANG_AUTO"))
        langDe.text:SetText(L("LANG_GERMAN"))
        langEn.text:SetText(L("LANG_ENGLISH"))
        aboutTitle:SetText(L("TITLE"))
        aboutText:SetText(L("ABOUT_TEXT"))
    end
    local function setTab(mode)
        settingsPage:Hide()
        languagePage:Hide()
        aboutPage:Hide()
        tabSettings:Enable()
        tabLanguage:Enable()
        tabAbout:Enable()
        if mode == "about" then
            aboutPage:Show()
            tabAbout:Disable()
        elseif mode == "language" then
            languagePage:Show()
            tabLanguage:Disable()
        else
            settingsPage:Show()
            tabSettings:Disable()
        end
    end
    tabSettings:SetScript("OnClick", function()
        setTab("settings")
    end)
    tabLanguage:SetScript("OnClick", function()
        setTab("language")
    end)
    tabAbout:SetScript("OnClick", function()
        setTab("about")
    end)
    setTab("settings")
    f:SetScript("OnShow", function()
        if not db then
            ensureDB()
        end
        if not db then
            return
        end
        for _, cb in ipairs(checkboxes) do
            local v = db[cb.dbKey]
            cb:SetChecked(v and true or false)
        end
        local mode = db.language or "auto"
        langAuto:SetChecked(mode == "auto")
        langDe:SetChecked(mode == "de")
        langEn:SetChecked(mode == "en")
        if refreshOptionsTexts then
            refreshOptionsTexts()
        end
    end)
end

local function updateMinimapButtonPosition()
    if not minimapButton or not db or not db.minimap then
        return
    end
    minimapButton:ClearAllPoints()
    minimapButton:SetPoint(db.minimap.point or "TOPLEFT", Minimap, db.minimap.relPoint or "TOPLEFT", db.minimap.x or 0, db.minimap.y or 0)
end

local function createMinimapButton()
    if minimapButton or not Minimap then
        return
    end
    if not db then
        ensureDB()
    end
    if not db then
        return
    end
    local btn = CreateFrame("Button", "RLGearscoreMinimapButton", Minimap)
    minimapButton = btn
    btn:SetSize(24, 24)
    btn:SetFrameStrata("MEDIUM")
    btn:SetMovable(true)
    btn:EnableMouse(true)
    btn:SetClampedToScreen(true)
    local tex = btn:CreateTexture(nil, "ARTWORK")
    tex:SetAllPoints()
    tex:SetTexture("Interface\\AddOns\\rlgearscore\\img\\logo.png")
    btn.icon = tex
    btn:SetHighlightTexture("Interface\\Minimap\\UI-Minimap-ZoomButton-Highlight", "ADD")
    btn:SetScript("OnEnter", function(self)
        GameTooltip:SetOwner(self, "ANCHOR_LEFT")
        GameTooltip:AddLine(L("MINIMAP_TOOLTIP_TITLE"))
        GameTooltip:AddLine(L("MINIMAP_TOOLTIP_LEFT"), 0.8, 0.8, 0.8)
        GameTooltip:AddLine(L("MINIMAP_TOOLTIP_RIGHT"), 0.8, 0.8, 0.8)
        GameTooltip:Show()
    end)
    btn:SetScript("OnLeave", function()
        GameTooltip:Hide()
    end)
    btn:SetScript("OnClick", function(self, button)
        if not db then
            ensureDB()
        end
        if button == "RightButton" then
            if db then
                db.enabled = not db.enabled
            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()
        if not db then
            ensureDB()
        end
        if db then
            local point, _, relPoint, x, y = self:GetPoint()
            db.minimap.point = point
            db.minimap.relPoint = relPoint
            db.minimap.x = x
            db.minimap.y = y
        end
    end)
    updateMinimapButtonPosition()
end

local function hookTooltip(name, withUnit)
    local tip = _G[name]
    if not tip or tip.__RLGearscoreHooked then
        return
    end
    tip:HookScript("OnTooltipSetItem", addItemInfo)
    if withUnit and tip.GetUnit then
        tip:HookScript("OnTooltipSetUnit", addUnitInfo)
    end
    tip:HookScript("OnHide", onTooltipHide)
    tip.__RLGearscoreHooked = true
end
hookTooltip("GameTooltip", true)
hookTooltip("ShoppingTooltip1", false)
hookTooltip("ShoppingTooltip2", false)
hookTooltip("ItemRefTooltip", false)

SlashCmdList["RLGearscore"] = function(msg)
    ensureDB()
    local unit = "target"
    if not UnitExists(unit) or not UnitIsPlayer(unit) then
        unit = "player"
    end
    if not UnitExists(unit) or not UnitIsPlayer(unit) then
        DEFAULT_CHAT_FRAME:AddMessage(L("CHAT_NO_TARGET"), 1, 0.2, 0.2)
        return
    end
    local name, realm = UnitName(unit)
    local level = UnitLevel(unit) or 0
    local race = UnitRace(unit) or ""
    local classLoc = UnitClass(unit)
    if realm and realm ~= "" then
        name = name .. "-" .. realm
    end
    local avgLevel, totalScore, talentText = getAverageAndScoreForUnit(unit)
    local playerAvg, playerScore = getUnitAverageAndScore("player")
    local parts = {}
    table.insert(parts, string.format("%s (" .. L("CHAT_LEVEL_PATTERN") .. ")", name or "?", level, race, classLoc or ""))
    if avgLevel then
        local coloredAvg = colorByDifficulty(string.format("%.1f", avgLevel), avgLevel, playerAvg)
        table.insert(parts, "iLvl Ø: " .. coloredAvg)
    end
    if totalScore and totalScore > 0 then
        local coloredScore = colorByDifficulty(totalScore, totalScore, playerScore)
        table.insert(parts, "GS: " .. coloredScore)
    end
    if talentText then
        table.insert(parts, string.format(L("CHAT_TALENTS"), talentText))
    end
    local text = L("CHAT_PREFIX") .. " " .. table.concat(parts, " | ")
    DEFAULT_CHAT_FRAME:AddMessage(text, 0, 1, 1)
    msg = msg and msg:lower() or ""
    if msg == "group" or msg == "raid" or msg == "party" or msg == "say" then
        local channel
        if msg == "say" then
            channel = "SAY"
        elseif IsInRaid() then
            channel = "RAID"
        elseif IsInGroup() then
            channel = "PARTY"
        end
        if channel then
            SendChatMessage(text, channel)
        end
    end
end

SLASH_RLGearscore1 = "/rlgs"

local eventFrame = CreateFrame("Frame")
eventFrame:RegisterEvent("PLAYER_LOGIN")
eventFrame:RegisterEvent("INSPECT_READY")
eventFrame:SetScript("OnEvent", function(self, event, arg1)
    if event == "PLAYER_LOGIN" then
        ensureDB()
        createMinimapButton()
    elseif event == "INSPECT_READY" then
        handleInspectReady(arg1)
    end
end)
