local addonName, ns = ...

-- Cached globals
local UnitStat = UnitStat
local GetCombatRating = GetCombatRating
local issecretvalue = issecretvalue

-- True when value is a plain number that can be compared or used in math.
function ns.IsSafeNumber(value)
    if type(value) ~= "number" then
        return false
    end
    if issecretvalue and issecretvalue(value) then
        return false
    end
    return true
end

local function SafeNumber(value, fallback)
    if type(value) == "number" and issecretvalue and issecretvalue(value) then
        return nil
    end
    if ns.IsSafeNumber(value) and value >= 0 then
        return value
    end
    return fallback or 0
end

-- Localized stat display names provided by the WoW client (all 11 locales).
-- The first argument may be a single global name or a list of candidates
-- (first non-empty wins); the last argument is the English fallback.
local function StatName(globalName, fallback)
    if type(globalName) == "table" then
        for _, name in ipairs(globalName) do
            local value = _G[name]
            if type(value) == "string" and value ~= "" then
                return value
            end
        end
        return fallback
    end
    local value = _G[globalName]
    if type(value) == "string" and value ~= "" then
        return value
    end
    return fallback
end

-- Combat rating constants are global numbers defined by the client.
-- Wrapped lookups so a missing constant never errors.
local function Rating(constantName)
    local index = _G[constantName]
    if type(index) ~= "number" then
        return 0
    end
    local ok, value = pcall(GetCombatRating, index)
    if ok then
        return SafeNumber(value, 0)
    end
    return 0
end

local function PrimaryStat(index)
    local ok, _, effective = pcall(UnitStat, "player", index)
    if ok then
        return SafeNumber(effective, 0)
    end
    return 0
end

-- Returns the bonus percent from a combat rating, or nil.
local function RatingBonus(constantName)
    local index = _G[constantName]
    if type(index) ~= "number" or not GetCombatRatingBonus then
        return nil
    end
    local ok, value = pcall(GetCombatRatingBonus, index)
    if ok and ns.IsSafeNumber(value) then
        return value
    end
    return nil
end

-- Wraps a global getter that returns a percent value.
local function EffectFn(globalName)
    return function()
        local fn = _G[globalName]
        if type(fn) ~= "function" then return nil end
        local ok, value = pcall(fn)
        if ok and ns.IsSafeNumber(value) then
            return value
        end
        return nil
    end
end

-- Stat definitions. Order here is the master list used by the menu.
-- color: RGB 0-1 used for the chart segment and legend accent.
-- icon: RPGIcons texture path for the legend (TGA, no extension needed).
-- get: current rating value (drives the chart proportions).
-- getEffect: current percent effect shown in the tooltip (optional).
-- isPrimary: primary stats are huge compared to secondaries, off by default.
local ICON = "Interface\\AddOns\\StatOrb\\media\\RPGIcons\\"
ns.STAT_DEFS = {
    { key = "crit",        name = StatName("STAT_CRITICAL_STRIKE", "Critical Strike"), color = { 0.93, 0.36, 0.32 }, icon = ICON .. "luck",     get = function() return Rating("CR_CRIT_SPELL") end,                  getEffect = EffectFn("GetCritChance") },
    { key = "haste",       name = StatName("STAT_HASTE", "Haste"),                     color = { 0.30, 0.74, 0.96 }, icon = ICON .. "wait",     get = function() return Rating("CR_HASTE_SPELL") end,                 getEffect = EffectFn("GetHaste") },
    { key = "mastery",     name = StatName("STAT_MASTERY", "Mastery"),                 color = { 0.69, 0.45, 0.95 }, icon = ICON .. "will",     get = function() return Rating("CR_MASTERY") end,                     getEffect = EffectFn("GetMasteryEffect") },
    { key = "versatility", name = StatName("STAT_VERSATILITY", "Versatility"),         color = { 0.42, 0.84, 0.46 }, icon = ICON .. "buff",     get = function() return Rating("CR_VERSATILITY_DAMAGE_DONE") end,      getEffect = function() return RatingBonus("CR_VERSATILITY_DAMAGE_DONE") end },
    { key = "leech",       name = StatName("STAT_LIFESTEAL", "Leech"),                 color = { 0.85, 0.30, 0.55 }, icon = ICON .. "charm",    get = function() return Rating("CR_LIFESTEAL") end,                   getEffect = function() return RatingBonus("CR_LIFESTEAL") end },
    { key = "avoidance",   name = StatName("STAT_AVOIDANCE", "Avoidance"),             color = { 0.95, 0.74, 0.25 }, icon = ICON .. "defense",  get = function() return Rating("CR_AVOIDANCE") end,                   getEffect = function() return RatingBonus("CR_AVOIDANCE") end },
    { key = "speed",       name = StatName("STAT_SPEED", "Speed"),                     color = { 0.55, 0.85, 0.85 }, icon = ICON .. "escape",   get = function() return Rating("CR_SPEED") end,                       getEffect = function() return RatingBonus("CR_SPEED") end },
    { key = "strength",    name = StatName({ "SPELL_STAT1_NAME", "ITEM_MOD_STRENGTH_SHORT", "STRENGTH" }, "Strength"),    color = { 0.78, 0.61, 0.43 }, icon = ICON .. "strength", get = function() return PrimaryStat(1) end, isPrimary = true },
    { key = "agility",     name = StatName({ "SPELL_STAT2_NAME", "ITEM_MOD_AGILITY_SHORT", "AGILITY" }, "Agility"),        color = { 0.61, 0.86, 0.35 }, icon = ICON .. "agility",  get = function() return PrimaryStat(2) end, isPrimary = true },
    { key = "stamina",     name = StatName({ "SPELL_STAT3_NAME", "ITEM_MOD_STAMINA_SHORT", "STAMINA" }, "Stamina"),        color = { 0.50, 0.60, 0.75 }, icon = ICON .. "health",   get = function() return PrimaryStat(3) end, isPrimary = true },
    { key = "intellect",   name = StatName({ "SPELL_STAT4_NAME", "ITEM_MOD_INTELLECT_SHORT", "INTELLECT" }, "Intellect"),  color = { 0.40, 0.66, 0.95 }, icon = ICON .. "magic",    get = function() return PrimaryStat(4) end, isPrimary = true },
}

-- Fast lookup by key.
ns.STAT_BY_KEY = {}
for _, def in ipairs(ns.STAT_DEFS) do
    ns.STAT_BY_KEY[def.key] = def
end

-- Returns the effect percent for a stat key, or nil when not applicable.
function ns.GetStatEffect(key)
    local def = ns.STAT_BY_KEY[key]
    if not def or not def.getEffect then
        return nil
    end
    local ok, value = pcall(def.getEffect)
    if ok and ns.IsSafeNumber(value) then
        return value
    end
    return nil
end

-- Stat priority per specialization (by specID), ordered most -> least important.
-- Mirrors common community stat priority lists (primary stat first).
ns.PRIORITY = {
    -- Warrior
    [71]  = { "strength", "crit", "haste", "mastery", "versatility" },     -- Arms
    [72]  = { "strength", "mastery", "haste", "versatility", "crit" },     -- Fury
    [73]  = { "strength", "haste", "crit", "versatility", "mastery" },     -- Protection
    -- Paladin
    [65]  = { "intellect", "haste", "mastery", "crit", "versatility" },    -- Holy
    [66]  = { "strength", "haste", "mastery", "versatility", "crit" },     -- Protection
    [70]  = { "strength", "mastery", "haste", "crit", "versatility" },     -- Retribution
    -- Hunter
    [253] = { "agility", "crit", "haste", "versatility", "mastery" },      -- Beast Mastery
    [254] = { "agility", "crit", "mastery", "versatility", "haste" },      -- Marksmanship
    [255] = { "agility", "mastery", "crit", "haste", "versatility" },      -- Survival
    -- Rogue
    [259] = { "agility", "crit", "mastery", "haste", "versatility" },      -- Assassination
    [260] = { "agility", "versatility", "haste", "crit", "mastery" },      -- Outlaw
    [261] = { "agility", "haste", "crit", "mastery", "versatility" },      -- Subtlety
    -- Priest
    [256] = { "intellect", "haste", "crit", "mastery", "versatility" },    -- Discipline
    [257] = { "intellect", "crit", "versatility", "mastery", "haste" },    -- Holy
    [258] = { "intellect", "haste", "mastery", "crit", "versatility" },    -- Shadow
    -- Shaman
    [262] = { "intellect", "mastery", "haste", "versatility", "crit" },    -- Elemental
    [263] = { "agility", "mastery", "haste", "crit", "versatility" },      -- Enhancement
    [264] = { "intellect", "haste", "crit", "versatility", "mastery" },    -- Restoration
    -- Mage
    [62]  = { "intellect", "mastery", "crit", "versatility", "haste" },    -- Arcane
    [63]  = { "intellect", "haste", "mastery", "crit", "versatility" },    -- Fire
    [64]  = { "intellect", "mastery", "crit", "versatility", "haste" },    -- Frost
    -- Warlock
    [265] = { "intellect", "mastery", "haste", "crit", "versatility" },    -- Affliction
    [266] = { "intellect", "haste", "crit", "mastery", "versatility" },    -- Demonology
    [267] = { "haste", "crit", "intellect", "mastery", "versatility" },    -- Destruction
    -- Druid
    [102] = { "intellect", "mastery", "haste", "versatility", "crit" },    -- Balance
    [103] = { "agility", "mastery", "crit", "haste", "versatility" },      -- Feral
    [104] = { "agility", "stamina", "haste", "versatility", "mastery", "crit" }, -- Guardian
    [105] = { "intellect", "haste", "mastery", "versatility", "crit" },    -- Restoration
    -- Monk
    [268] = { "agility", "versatility", "crit", "mastery", "haste" },      -- Brewmaster
    [270] = { "intellect", "haste", "crit", "versatility", "mastery" },    -- Mistweaver
    [269] = { "agility", "crit", "haste", "mastery", "versatility" },      -- Windwalker
    -- Death Knight
    [250] = { "strength", "haste", "crit", "versatility", "mastery" },     -- Blood
    [251] = { "strength", "crit", "mastery", "haste", "versatility" },     -- Frost
    [252] = { "strength", "mastery", "crit", "haste", "versatility" },     -- Unholy
    -- Demon Hunter
    [577]  = { "agility", "crit", "haste", "versatility", "mastery" },     -- Havoc
    [581]  = { "agility", "haste", "versatility", "crit", "mastery" },     -- Vengeance
    [1480] = { "intellect", "mastery", "haste", "crit", "versatility" },   -- Devourer
    -- Evoker
    [1467] = { "intellect", "haste", "crit", "mastery", "versatility" },   -- Devastation
    [1468] = { "intellect", "mastery", "crit", "haste", "versatility" },   -- Preservation
    [1473] = { "intellect", "crit", "haste", "mastery", "versatility" },   -- Augmentation
}

-- Fallback priority when the spec is unknown.
ns.PRIORITY_FALLBACK = { "crit", "haste", "mastery", "versatility" }

-- Returns the ordered priority key list for the player's current spec.
function ns.GetCurrentPriority()
    local specIndex = GetSpecialization and GetSpecialization()
    if specIndex then
        local specID = GetSpecializationInfo and GetSpecializationInfo(specIndex)
        if specID and ns.PRIORITY[specID] then
            return ns.PRIORITY[specID]
        end
    end
    return ns.PRIORITY_FALLBACK
end

-- Returns specID, localized name and icon texture for the current spec.
function ns.GetCurrentSpecInfo()
    local specIndex = GetSpecialization and GetSpecialization()
    if not specIndex then return nil end
    local ok, id, name, _, icon = pcall(GetSpecializationInfo, specIndex)
    if ok and id then
        return id, name, icon
    end
    return nil
end

-- Builds a colored "Stat1 > Stat2 > ..." priority string for the current spec.
function ns.GetPriorityString()
    local priority = ns.GetCurrentPriority()
    local parts = {}
    for _, key in ipairs(priority) do
        local def = ns.STAT_BY_KEY[key]
        if def then
            local c = def.color
            parts[#parts + 1] = ("|cff%02x%02x%02x%s|r"):format(
                c[1] * 255, c[2] * 255, c[3] * 255, def.name)
        end
    end
    return table.concat(parts, " |cff808080>|r ")
end
