--[[
    Commander 3.0 - Character Data Source

    Provides access to player character statistics.
    Commands: stats, info

    Uses UnitStat, GetCritChance, GetMastery, etc. APIs
]]

local ADDON_NAME, C3 = ...

-- Use shared utilities
local Colorize = function(...) return C3.Colors.Colorize(...) end
local GetThemeColor = function(...) return C3.Colors.GetColor(...) end

-------------------------------------------------------------------------------
-- PlayerStat Type Registration
-------------------------------------------------------------------------------

C3.Types:Register("PlayerStat", {
    description = "Player character statistic",
    source = "stats",
    properties = {
        { "name", "Stat name" },
        { "value", "Raw value or rating" },
        { "percent", "Percentage value (if applicable)" },
        { "category", "Category: attribute, offense, defense, tertiary, resource" },
        { "order", "Display order within category" },
    },
})

C3.Formatter:Register("PlayerStat", {
    format = function(obj)
        local nameColor = GetThemeColor("accent.info") or "81A1C1"
        local valueColor = GetThemeColor("accent.success") or "A3BE8C"
        local dimColor = GetThemeColor("status.dim") or "4C566A"

        local nameStr = string.format("|cFF%s%-18s|r", nameColor, obj.name or "Unknown")

        -- Format value based on whether we have a percentage
        local valueStr
        if obj.percent ~= nil then
            valueStr = string.format("|cFF%s%6.2f%%|r", valueColor, obj.percent)
            if obj.value and obj.value > 0 then
                valueStr = valueStr .. string.format(" |cFF%s(%s)|r", dimColor, BreakUpLargeNumbers(math.floor(obj.value)))
            end
        elseif obj.value then
            if obj.value == math.floor(obj.value) then
                valueStr = string.format("|cFF%s%s|r", valueColor, BreakUpLargeNumbers(math.floor(obj.value)))
            else
                valueStr = string.format("|cFF%s%.2f|r", valueColor, obj.value)
            end
        else
            valueStr = Colorize("--", "status.dim")
        end

        return nameStr .. " " .. valueStr
    end,
    list = function(obj)
        if obj.percent then
            return string.format("%s: %.2f%%", obj.name or "?", obj.percent)
        elseif obj.value then
            return string.format("%s: %s", obj.name or "?", tostring(obj.value))
        end
        return obj.name or "?"
    end,
    compact = function(obj)
        if obj.percent then
            return string.format("%.1f%%", obj.percent)
        elseif obj.value then
            return tostring(obj.value)
        end
        return "?"
    end
})

-------------------------------------------------------------------------------
-- Stat Collection Helpers
-------------------------------------------------------------------------------

local STAT_CATEGORIES = {
    attribute = 1,
    offense = 2,
    defense = 3,
    tertiary = 4,
    resource = 5,
}

local function createStat(name, value, percent, category, order)
    return C3.Types.Create("PlayerStat", {
        name = name,
        value = value,
        percent = percent,
        category = category,
        order = order,
    })
end

local function getAttributeStats()
    local stats = {}
    local unit = "player"

    -- Primary attributes
    local str = UnitStat(unit, 1)
    local agi = UnitStat(unit, 2)
    local sta = UnitStat(unit, 3)
    local int = UnitStat(unit, 4)

    stats[#stats + 1] = createStat("Strength", str, nil, "attribute", 1)
    stats[#stats + 1] = createStat("Agility", agi, nil, "attribute", 2)
    stats[#stats + 1] = createStat("Stamina", sta, nil, "attribute", 3)
    stats[#stats + 1] = createStat("Intellect", int, nil, "attribute", 4)

    -- Armor
    local baseArmor, effectiveArmor = UnitArmor(unit)
    stats[#stats + 1] = createStat("Armor", effectiveArmor, nil, "attribute", 5)

    return stats
end

local function getOffenseStats()
    local stats = {}
    local unit = "player"

    -- Attack/Spell Power
    local base, posBuff, negBuff = UnitAttackPower(unit)
    local attackPower = base + posBuff + negBuff
    stats[#stats + 1] = createStat("Attack Power", attackPower, nil, "offense", 1)

    -- Spell Power (max across all schools)
    local maxSpellPower = 0
    for i = 2, 7 do  -- Schools: Holy, Fire, Nature, Frost, Shadow, Arcane
        local sp = GetSpellBonusDamage(i)
        if sp > maxSpellPower then maxSpellPower = sp end
    end
    stats[#stats + 1] = createStat("Spell Power", maxSpellPower, nil, "offense", 2)

    -- Critical Strike
    local critChance = GetCritChance()
    local critRating = GetCombatRating(CR_CRIT_MELEE)
    stats[#stats + 1] = createStat("Critical Strike", critRating, critChance, "offense", 3)

    -- Haste
    local hastePercent = GetHaste()
    local hasteRating = GetCombatRating(CR_HASTE_MELEE)
    stats[#stats + 1] = createStat("Haste", hasteRating, hastePercent, "offense", 4)

    -- Mastery
    local masteryEffect, masteryCoeff = GetMasteryEffect()
    local masteryRating = GetCombatRating(CR_MASTERY)
    stats[#stats + 1] = createStat("Mastery", masteryRating, masteryEffect, "offense", 5)

    -- Versatility (damage/healing)
    local versatilityDmg = GetCombatRatingBonus(CR_VERSATILITY_DAMAGE_DONE)
    local versatilityRating = GetCombatRating(CR_VERSATILITY_DAMAGE_DONE)
    stats[#stats + 1] = createStat("Versatility", versatilityRating, versatilityDmg, "offense", 6)

    return stats
end

local function getDefenseStats()
    local stats = {}
    local unit = "player"

    -- Dodge
    local dodgeChance = GetDodgeChance()
    local dodgeRating = GetCombatRating(CR_DODGE)
    stats[#stats + 1] = createStat("Dodge", dodgeRating, dodgeChance, "defense", 1)

    -- Parry
    local parryChance = GetParryChance()
    local parryRating = GetCombatRating(CR_PARRY)
    stats[#stats + 1] = createStat("Parry", parryRating, parryChance, "defense", 2)

    -- Block
    local blockChance = GetBlockChance()
    stats[#stats + 1] = createStat("Block", nil, blockChance, "defense", 3)

    -- Versatility (damage reduction)
    local versatilityDR = GetCombatRatingBonus(CR_VERSATILITY_DAMAGE_TAKEN)
    stats[#stats + 1] = createStat("Vers (DR)", nil, versatilityDR, "defense", 4)

    -- Armor damage reduction (approximate at level 80 boss)
    local _, effectiveArmor = UnitArmor(unit)
    local level = UnitLevel(unit)
    local armorReduction = 0
    if PaperDollFrame_GetArmorReduction then
        armorReduction = PaperDollFrame_GetArmorReduction(effectiveArmor, level + 3)
    elseif effectiveArmor > 0 then
        -- Fallback formula: K value for level+3 mob
        local K = 467.5 * (level + 3) - 22167.5
        if K > 0 then
            armorReduction = effectiveArmor / (effectiveArmor + K) * 100
        end
    end
    stats[#stats + 1] = createStat("Armor (DR)", nil, armorReduction, "defense", 5)

    return stats
end

local function getTertiaryStats()
    local stats = {}

    -- Speed
    local speed = GetSpeed and GetSpeed() or 0
    stats[#stats + 1] = createStat("Speed", nil, speed, "tertiary", 1)

    -- Leech
    local leech = GetLifesteal and GetLifesteal() or 0
    stats[#stats + 1] = createStat("Leech", nil, leech, "tertiary", 2)

    -- Avoidance
    local avoidance = GetAvoidance and GetAvoidance() or 0
    stats[#stats + 1] = createStat("Avoidance", nil, avoidance, "tertiary", 3)

    -- Movement speed (actual)
    local currentSpeed, runSpeed, flightSpeed, swimSpeed = GetUnitSpeed("player")
    local baseSpeed = 7  -- 7 yards/sec base
    local movementPct = runSpeed / baseSpeed * 100
    stats[#stats + 1] = createStat("Movement", nil, movementPct, "tertiary", 4)

    return stats
end

local function getResourceStats()
    local stats = {}

    -- GCD
    local hastePercent = math.max(GetMeleeHaste(), UnitSpellHaste("player"))
    local gcd = math.max(0.75, 1.5 * 100 / (100 + hastePercent))
    stats[#stats + 1] = createStat("GCD", gcd, nil, "resource", 1)

    -- Health (uses Secrets module for WoW 12.0+ compatibility)
    local health
    if C3.Secrets then
        health = C3.Secrets.UnitHealthMax("player")
    else
        health = UnitHealthMax("player")
    end
    stats[#stats + 1] = createStat("Health", health, nil, "resource", 2)

    -- Power (mana/rage/energy/etc.) - uses Secrets module for WoW 12.0+
    local powerType = UnitPowerType("player")
    local powerMax
    if C3.Secrets then
        powerMax = C3.Secrets.UnitPowerMax("player")
    else
        powerMax = UnitPowerMax("player")
    end
    local powerName = "Power"
    if powerType == 0 then powerName = "Mana"
    elseif powerType == 1 then powerName = "Rage"
    elseif powerType == 2 then powerName = "Focus"
    elseif powerType == 3 then powerName = "Energy"
    elseif powerType == 4 then powerName = "Combo Points"
    elseif powerType == 6 then powerName = "Runic Power"
    end
    stats[#stats + 1] = createStat(powerName, powerMax, nil, "resource", 3)

    return stats
end

-------------------------------------------------------------------------------
-- stats - Show player statistics
-------------------------------------------------------------------------------

C3.Command:Define({
    name = "stats",
    description = "Show player character statistics",
    category = "data",
    producesType = "PlayerStat",
    acceptsInput = false,
    flags = {
        offense = { short = "o", description = "Show only offense stats" },
        defense = { short = "d", description = "Show only defense stats" },
        tertiary = { short = "t", description = "Show only tertiary stats" },
        attributes = { short = "a", description = "Show only attributes" },
        flat = { short = "f", description = "Flat list without category headers" },
    },
    execute = function(ctx)
        local offenseOnly = ctx:HasFlag("offense") or ctx:HasFlag("o")
        local defenseOnly = ctx:HasFlag("defense") or ctx:HasFlag("d")
        local tertiaryOnly = ctx:HasFlag("tertiary") or ctx:HasFlag("t")
        local attributesOnly = ctx:HasFlag("attributes") or ctx:HasFlag("a")
        local flatMode = ctx:HasFlag("flat") or ctx:HasFlag("f")

        local results = {}
        local showAll = not (offenseOnly or defenseOnly or tertiaryOnly or attributesOnly)

        -- Helper to add category header
        local function addHeader(name)
            if not flatMode then
                table.insert(results, C3.Types.Create("Text", {
                    content = Colorize("── " .. name .. " ──", "accent.warning")
                }))
            end
        end

        -- Attributes
        if showAll or attributesOnly then
            addHeader("Attributes")
            for _, stat in ipairs(getAttributeStats()) do
                table.insert(results, stat)
            end
        end

        -- Offense
        if showAll or offenseOnly then
            addHeader("Offense")
            for _, stat in ipairs(getOffenseStats()) do
                table.insert(results, stat)
            end
        end

        -- Defense
        if showAll or defenseOnly then
            addHeader("Defense")
            for _, stat in ipairs(getDefenseStats()) do
                table.insert(results, stat)
            end
        end

        -- Tertiary
        if showAll or tertiaryOnly then
            addHeader("Tertiary")
            for _, stat in ipairs(getTertiaryStats()) do
                table.insert(results, stat)
            end
        end

        -- Resources
        if showAll then
            addHeader("Resources")
            for _, stat in ipairs(getResourceStats()) do
                table.insert(results, stat)
            end
        end

        return results
    end
})

-------------------------------------------------------------------------------
-- info - Show character summary
-------------------------------------------------------------------------------

C3.Command:Define({
    name = "info",
    description = "Show character summary",
    category = "data",
    acceptsInput = false,
    execute = function(ctx)
        local unit = "player"
        local name = UnitName(unit)
        local level = UnitLevel(unit)
        local className, classFile = UnitClass(unit)
        local raceName = UnitRace(unit)

        -- Get spec info
        local specName = "None"
        local specIndex = GetSpecialization()
        if specIndex then
            local _, specNameResult = GetSpecializationInfo(specIndex)
            specName = specNameResult or "Unknown"
        end

        -- Get item level
        local overall, equipped = GetAverageItemLevel()

        -- Class color
        local classColor = RAID_CLASS_COLORS[classFile]
        local colorHex = classColor and classColor.colorStr:sub(3) or "FFFFFF"

        local results = {}

        -- Character name with class color
        table.insert(results, C3.Types.Create("Text", {
            content = string.format("|cFF%s%s|r - Level %d %s %s",
                colorHex, name, level, raceName, className)
        }))

        -- Spec
        table.insert(results, C3.Types.Create("Text", {
            content = string.format("Specialization: %s", Colorize(specName, "accent.primary"))
        }))

        -- Item Level
        table.insert(results, C3.Types.Create("Text", {
            content = string.format("Item Level: %s equipped (%s overall)",
                Colorize(string.format("%.1f", equipped), "accent.success"),
                Colorize(string.format("%.1f", overall), "accent.info"))
        }))

        -- Health/Power
        local health = UnitHealthMax(unit)
        local powerType = UnitPowerType(unit)
        local powerMax = UnitPowerMax(unit)
        local powerName = "Power"
        if powerType == 0 then powerName = "Mana"
        elseif powerType == 1 then powerName = "Rage"
        elseif powerType == 2 then powerName = "Focus"
        elseif powerType == 3 then powerName = "Energy"
        elseif powerType == 6 then powerName = "Runic Power"
        end

        table.insert(results, C3.Types.Create("Text", {
            content = string.format("Health: %s  %s: %s",
                Colorize(BreakUpLargeNumbers(health), "accent.success"),
                powerName,
                Colorize(BreakUpLargeNumbers(powerMax), "accent.info"))
        }))

        -- Location
        local zone = GetZoneText() or "Unknown"
        local subzone = GetSubZoneText()
        local locationStr = zone
        if subzone and subzone ~= "" and subzone ~= zone then
            locationStr = subzone .. ", " .. zone
        end

        table.insert(results, C3.Types.Create("Text", {
            content = string.format("Location: %s", Colorize(locationStr, "accent.warning"))
        }))

        -- Gold
        local gold = GetMoney()
        local goldAmount = math.floor(gold / 10000)
        local silverAmount = math.floor((gold % 10000) / 100)
        local copperAmount = gold % 100

        table.insert(results, C3.Types.Create("Text", {
            content = string.format("Gold: |cFFFFD700%s|rg |cFFC0C0C0%d|rs |cFFB87333%d|rc",
                BreakUpLargeNumbers(goldAmount), silverAmount, copperAmount)
        }))

        return results
    end
})

return true
