local _, ns = ...
local MythicTools = ns.MythicTools
local UI = ns.UI

local COLORS = UI.COLORS
local ClipChildren = UI.ClipChildren
local CreateAceDropdownWidget = UI.CreateAceDropdownWidget
local CreateFont = UI.CreateFont
local CreateStatsCard = UI.CreateStatsCard
local CreateStatsDungeonRow = UI.CreateStatsDungeonRow
local CreateStatsTitleBar = UI.CreateStatsTitleBar
local FormatTotalTime = UI.FormatTotalTime
local MAX_STATS_CLASS_ROWS = UI.MAX_STATS_CLASS_ROWS
local MAX_STATS_DUNGEON_ROWS = UI.MAX_STATS_DUNGEON_ROWS
local MAX_STATS_TEAMMATE_ROWS = UI.MAX_STATS_TEAMMATE_ROWS
local SEASON_FILTER_OPTIONS = UI.SEASON_FILTER_OPTIONS
local STATS_CLASS_ROW_H = UI.STATS_CLASS_ROW_H
local STATS_CONTENT_H = UI.STATS_CONTENT_H
local STATS_DUNGEON_ROW_H = UI.STATS_DUNGEON_ROW_H
local STATS_DUNGEON_SECTION_H = UI.STATS_DUNGEON_SECTION_H
local STATS_OVERVIEW_H = UI.STATS_OVERVIEW_H
local STATS_PAD = UI.STATS_PAD
local STATS_SECTION_TITLE_H = UI.STATS_SECTION_TITLE_H
local STATS_TEAMMATE_ROW_H = UI.STATS_TEAMMATE_ROW_H
local STATS_TEAMMATE_SECTION_H = UI.STATS_TEAMMATE_SECTION_H
local STATS_TWOCOL_H = UI.STATS_TWOCOL_H
local SetAceDropdownValue = UI.SetAceDropdownValue
local SetTextColor = UI.SetTextColor
local StyleAceDropdownWidget = UI.StyleAceDropdownWidget
local UpdateDungeonRowBar = UI.UpdateDungeonRowBar
local WHITE_TEXTURE = UI.WHITE_TEXTURE
local floor = UI.floor
local max = UI.max
local min = UI.min

function MythicTools:ComputeStatsData(filters)
    filters = filters or {}
    local cacheKey = table.concat({
        tostring(self._historyDataRevision or 0),
        filters.season or "",
        filters.character or "",
    }, "\031")
    if self._statsDataCache and self._statsDataCache.key == cacheKey then
        return self._statsDataCache.value
    end

    local runs = (self.db and self.db.runs) or {}
    local total = 0
    local timed, overtime, abandoned = 0, 0, 0
    local totalLevel, countedLevel, bestTimed = 0, 0, 0
    local totalTimeMS, totalDeaths = 0, 0
    local dungeons, classes, teammates, characters = {}, {}, {}, {}

    for _, run in ipairs(runs) do
        if type(run) == "table" then
            local include = true
            local ownerName = self:NormalizePlayerName(run.ownerCharacter) or self:TrimText(run.ownerCharacter)
            if filters.season and filters.season ~= "" and filters.season ~= "all" then
                include = self:GetRunSeason(run) == filters.season
            end
            if include and filters.character and filters.character ~= "" and filters.character ~= "all" then
                include = ownerName == filters.character
            end
            if include then
            total = total + 1
            local result = run.result or "abandoned"
            local isAbandoned = result == "abandoned"
            local isTimed = result == "timed"
            if isTimed then timed = timed + 1
            elseif isAbandoned then abandoned = abandoned + 1
            else overtime = overtime + 1 end
            if not isAbandoned and (run.level or 0) > 0 then
                totalLevel = totalLevel + run.level
                countedLevel = countedLevel + 1
            end
            if isTimed and (run.level or 0) > bestTimed then bestTimed = run.level end
            if not isAbandoned then totalTimeMS = totalTimeMS + (run.timeMS or 0) end
            local ownerStat = ownerName and run.playerStats and run.playerStats[ownerName] or nil
            totalDeaths = totalDeaths + (tonumber(ownerStat and ownerStat.deaths) or 0)
            local characterEntry
            if ownerName and ownerName ~= "" then
                characterEntry = characters[ownerName]
                if not characterEntry then
                    characterEntry = {
                        fullName = ownerName,
                        name = self:GetShortName(ownerName),
                        totalRuns = 0,
                        timedRuns = 0,
                        bestTimed = 0,
                        totalLevel = 0,
                        countedLevel = 0,
                        dungeons = {},
                        totalDps = 0,
                        countedDps = 0,
                        totalHps = 0,
                        countedHps = 0,
                        specs = {},
                    }
                    characters[ownerName] = characterEntry
                end
                characterEntry.totalRuns = characterEntry.totalRuns + 1
                if isTimed then
                    characterEntry.timedRuns = characterEntry.timedRuns + 1
                    characterEntry.bestTimed = max(characterEntry.bestTimed or 0, tonumber(run.level) or 0)
                end
                if not isAbandoned and (run.level or 0) > 0 then
                    characterEntry.totalLevel = characterEntry.totalLevel + run.level
                    characterEntry.countedLevel = characterEntry.countedLevel + 1
                end
                if run.dungeonName and run.dungeonName ~= "" then
                    characterEntry.dungeons[run.dungeonName] = (characterEntry.dungeons[run.dungeonName] or 0) + 1
                end
            end
            local dName = type(run.dungeonName) == "string" and run.dungeonName ~= "" and run.dungeonName
            if dName then
                if not dungeons[dName] then
                    dungeons[dName] = {name=dName, count=0, timed=0, overtime=0, abandoned=0, totalTimeMS=0, countedTime=0}
                end
                local d = dungeons[dName]
                d.count = d.count + 1
                if isTimed then d.timed = d.timed + 1
                elseif isAbandoned then d.abandoned = d.abandoned + 1
                else d.overtime = d.overtime + 1 end
                if not isAbandoned and (run.timeMS or 0) > 0 then
                    d.totalTimeMS = d.totalTimeMS + run.timeMS
                    d.countedTime = d.countedTime + 1
                end
            end
            for playerName, stat in pairs(run.playerStats or {}) do
                if type(stat) == "table" and not self:IsOwnedCharacter(playerName) then
                    if stat.classFilename then
                        classes[stat.classFilename] = (classes[stat.classFilename] or 0) + 1
                    end
                    local sn = stat.shortName or self:GetShortName(playerName)
                    if sn and sn ~= "" then
                        if not teammates[sn] then
                            teammates[sn] = {name=sn, count=0, classFilename=stat.classFilename}
                        end
                        teammates[sn].count = teammates[sn].count + 1
                        if stat.classFilename then teammates[sn].classFilename = stat.classFilename end
                    end
                elseif type(stat) == "table" and characterEntry and playerName == ownerName then
                    local dps = stat.damage ~= nil and self:GetPlayerDPS(run, stat) or nil
                    local hps = stat.healing ~= nil and self:GetPlayerHPS(run, stat) or nil
                    if dps and dps > 0 then
                        characterEntry.totalDps = characterEntry.totalDps + dps
                        characterEntry.countedDps = characterEntry.countedDps + 1
                    end
                    if hps and hps > 0 then
                        characterEntry.totalHps = characterEntry.totalHps + hps
                        characterEntry.countedHps = characterEntry.countedHps + 1
                    end
                    local specKey = tostring(stat.specID or stat.specName or "unknown")
                    local specEntry = characterEntry.specs[specKey]
                    if not specEntry then
                        specEntry = {
                            name = stat.specName or (stat.specID and ("Spec " .. tostring(stat.specID))) or "Unknown spec",
                            totalDps = 0,
                            countedDps = 0,
                            totalHps = 0,
                            countedHps = 0,
                        }
                        characterEntry.specs[specKey] = specEntry
                    end
                    if dps and dps > 0 then
                        specEntry.totalDps = specEntry.totalDps + dps
                        specEntry.countedDps = specEntry.countedDps + 1
                    end
                    if hps and hps > 0 then
                        specEntry.totalHps = specEntry.totalHps + hps
                        specEntry.countedHps = specEntry.countedHps + 1
                    end
                end
            end
            end
        end
    end

    local sortedDungeons = {}
    for _, d in pairs(dungeons) do
        d.avgTimeMS = d.countedTime > 0 and (d.totalTimeMS / d.countedTime) or 0
        sortedDungeons[#sortedDungeons + 1] = d
    end
    table.sort(sortedDungeons, function(a, b) return a.count > b.count end)

    local sortedClasses = {}
    for cf, cnt in pairs(classes) do
        sortedClasses[#sortedClasses + 1] = {classFilename=cf, count=cnt}
    end
    table.sort(sortedClasses, function(a, b) return a.count > b.count end)

    local sortedTeammates = {}
    for _, t in pairs(teammates) do sortedTeammates[#sortedTeammates + 1] = t end
    table.sort(sortedTeammates, function(a, b) return a.count > b.count end)

    local sortedCharacters = {}
    for _, character in pairs(characters) do
        local topDungeon, topDungeonCount = nil, 0
        for dungeonName, count in pairs(character.dungeons or {}) do
            if count > topDungeonCount then
                topDungeon = dungeonName
                topDungeonCount = count
            end
        end
        local topSpec, topSpecValue = nil, 0
        for _, specEntry in pairs(character.specs or {}) do
            local specDps = specEntry.countedDps > 0 and (specEntry.totalDps / specEntry.countedDps) or 0
            local specHps = specEntry.countedHps > 0 and (specEntry.totalHps / specEntry.countedHps) or 0
            local value = max(specDps, specHps)
            if value > topSpecValue then
                topSpec = {
                    name = specEntry.name,
                    averageDps = specDps,
                    averageHps = specHps,
                }
                topSpecValue = value
            end
        end
        character.timedPct = character.totalRuns > 0 and (character.timedRuns / character.totalRuns * 100) or 0
        character.averageLevel = character.countedLevel > 0 and (character.totalLevel / character.countedLevel) or 0
        character.averageDps = character.countedDps > 0 and (character.totalDps / character.countedDps) or 0
        character.averageHps = character.countedHps > 0 and (character.totalHps / character.countedHps) or 0
        character.topDungeon = topDungeon
        character.topSpec = topSpec
        sortedCharacters[#sortedCharacters + 1] = character
    end
    table.sort(sortedCharacters, function(a, b)
        if (a.bestTimed or 0) ~= (b.bestTimed or 0) then
            return (a.bestTimed or 0) > (b.bestTimed or 0)
        end
        return (a.totalRuns or 0) > (b.totalRuns or 0)
    end)

    local data = {
        total = total, timed = timed, overtime = overtime, abandoned = abandoned,
        timedPct = total > 0 and (timed / total * 100) or 0,
        avgLevel = countedLevel > 0 and (totalLevel / countedLevel) or 0,
        bestTimed = bestTimed, totalTimeMS = totalTimeMS, totalDeaths = totalDeaths,
        dungeons = sortedDungeons, classes = sortedClasses, teammates = sortedTeammates, characters = sortedCharacters,
    }
    self._statsDataCache = {
        key = cacheKey,
        value = data,
    }
    return data
end

function MythicTools:BuildStatsPage(parent)
    local page = CreateFrame("Frame", nil, parent)
    page:SetAllPoints(parent)
    ClipChildren(page)

    -- Header
    local headerCard = CreateFrame("Frame", nil, page)
    headerCard:SetPoint("TOPLEFT", 12, -12)
    headerCard:SetPoint("TOPRIGHT", -12, -12)
    headerCard:SetHeight(62)
    self:ApplySurface(headerCard, COLORS.sectionBG, COLORS.surface, COLORS.accentSoft)
    local headerTitle = CreateFont(headerCard, 13, COLORS.accent)
    headerTitle:SetPoint("LEFT", 16, 0)
    headerTitle:SetText(self:L("UI_STATISTICS"))

    self.db.ui.statsFilters = self.db.ui.statsFilters or {}
    local statsCharacterOptions = self:GetStatsCharacterFilterOptions(self.db.ui.statsFilters.season or "all")
    self.db.ui.statsFilters.character = self:ResolveDropdownValueFromOptions(statsCharacterOptions, self.db.ui.statsFilters.character or "all", "all")
    self.ui.statsCharacterFilter = CreateAceDropdownWidget(self:L("UI_CHARACTER"), 210, statsCharacterOptions, self.db.ui.statsFilters.character, function(value)
        self.db.ui.statsFilters.character = value or "all"
        SetAceDropdownValue(self.ui.statsCharacterFilter, self.db.ui.statsFilters.character)
        self:RefreshStatsView()
    end)
    StyleAceDropdownWidget(self.ui.statsCharacterFilter)
    local statsCharacterFilterFrame = self.ui.statsCharacterFilter and self.ui.statsCharacterFilter.frame
    if statsCharacterFilterFrame then
        statsCharacterFilterFrame:SetParent(headerCard)
        statsCharacterFilterFrame:ClearAllPoints()
        statsCharacterFilterFrame:SetPoint("TOPRIGHT", headerCard, "TOPRIGHT", -16, -6)
        statsCharacterFilterFrame:SetHeight(50)
        statsCharacterFilterFrame:Show()
    end

    self.ui.statsSeasonFilter = CreateAceDropdownWidget(self:L("UI_SEASON"), 170, SEASON_FILTER_OPTIONS, (self.db.ui.statsFilters and self.db.ui.statsFilters.season) or "all", function(value)
        self.db.ui.statsFilters.season = value or "all"
        SetAceDropdownValue(self.ui.statsSeasonFilter, self.db.ui.statsFilters.season)
        self:RefreshStatsCharacterFilterOptions()
        self:RefreshStatsView()
    end)
    StyleAceDropdownWidget(self.ui.statsSeasonFilter)
    if self.ui.statsSeasonFilter and self.ui.statsSeasonFilter.frame then
        self.ui.statsSeasonFilter.frame:SetParent(headerCard)
        self.ui.statsSeasonFilter.frame:ClearAllPoints()
        if statsCharacterFilterFrame then
            self.ui.statsSeasonFilter.frame:SetPoint("TOPRIGHT", statsCharacterFilterFrame, "TOPLEFT", -8, 0)
        else
            self.ui.statsSeasonFilter.frame:SetPoint("TOPRIGHT", headerCard, "TOPRIGHT", -16, -6)
        end
        self.ui.statsSeasonFilter.frame:SetHeight(50)
        self.ui.statsSeasonFilter.frame:Show()
    end

    -- Scroll frame
    local scrollFrame = CreateFrame("ScrollFrame", nil, page)
    scrollFrame:SetPoint("TOPLEFT", 12, -86)
    scrollFrame:SetPoint("BOTTOMRIGHT", -20, 12)
    scrollFrame:EnableMouseWheel(true)
    self.ui.statsScrollFrame = scrollFrame

    -- Explicit content width: SetScrollChild breaks TOPRIGHT anchors (they resolve to 0).
    -- Derive from saved frame width: pageW = frameW - sidebarW(213), scrollFrame inset = 12+20 = 32
    local frameW = (self.db and self.db.ui and self.db.ui.width) or 1080
    local scrollW = max(600, frameW - 245)
    local sectionW = scrollW - 2 * STATS_PAD
    local leftColW = floor(sectionW * 0.37)
    local rightColW = sectionW - leftColW - STATS_PAD

    local content = CreateFrame("Frame", nil, scrollFrame)
    content:SetSize(scrollW, STATS_CONTENT_H)
    scrollFrame:SetScrollChild(content)
    self.ui.statsContent = content

    -- Thin scrollbar
    local scrollBar = CreateFrame("Slider", nil, page)
    scrollBar:SetOrientation("VERTICAL")
    scrollBar:SetWidth(6)
    scrollBar:SetPoint("TOPRIGHT", page, "TOPRIGHT", -12, -86)
    scrollBar:SetPoint("BOTTOMRIGHT", page, "BOTTOMRIGHT", -12, 12)
    scrollBar:SetMinMaxValues(0, 1)
    scrollBar:SetValue(0)
    scrollBar:Hide()
    local sbThumb = scrollBar:CreateTexture(nil, "ARTWORK")
    sbThumb:SetTexture(WHITE_TEXTURE)
    sbThumb:SetWidth(4)
    sbThumb:SetVertexColor(COLORS.accent[1], COLORS.accent[2], COLORS.accent[3], 0.65)
    scrollBar:SetThumbTexture(sbThumb)
    scrollBar:SetScript("OnValueChanged", function(self, value)
        scrollFrame:SetVerticalScroll(value)
    end)
    scrollFrame:SetScript("OnScrollRangeChanged", function(self, _, yRange)
        local m = max(0, yRange)
        scrollBar:SetMinMaxValues(0, m)
        scrollBar:SetShown(m > 0)
    end)
    scrollFrame:SetScript("OnMouseWheel", function(self, delta)
        local cur = scrollBar:GetValue()
        local _, maxVal = scrollBar:GetMinMaxValues()
        scrollBar:SetValue(max(0, min(cur - delta * 60, maxVal)))
    end)
    self.ui.statsScrollBar = scrollBar

    local y = -STATS_PAD

    -- ── SECTION 1: OVERVIEW ──────────────────────────────────────────────
    local OVERVIEW_LABELS = {"Total Runs", "Timed %", "Avg Key", "Best Key", "In-Key Time", "Deaths"}
    local NUM_OV = #OVERVIEW_LABELS
    local ovGap = 8
    local ovCardW = floor((sectionW - (NUM_OV - 1) * ovGap) / NUM_OV)
    local overviewRow = CreateFrame("Frame", nil, content)
    overviewRow:SetPoint("TOPLEFT", STATS_PAD, y)
    overviewRow:SetSize(sectionW, STATS_OVERVIEW_H)
    self.ui.statsOverviewCards = {}
    for i = 1, NUM_OV do
        local card = CreateFrame("Frame", nil, overviewRow)
        self:ApplySurface(card, COLORS.sectionBG, COLORS.surface, COLORS.accentSoft)
        card:SetPoint("TOPLEFT", (i - 1) * (ovCardW + ovGap), 0)
        card:SetSize(ovCardW, STATS_OVERVIEW_H)
        card.Value = CreateFont(card, 22, COLORS.text, "CENTER")
        card.Value:SetPoint("CENTER", 0, 12)
        card.Value:SetText("--")
        card.Label = CreateFont(card, 10, COLORS.subdued, "CENTER")
        card.Label:SetPoint("CENTER", 0, -12)
        card.Label:SetText(OVERVIEW_LABELS[i])
        self.ui.statsOverviewCards[i] = card
    end

    y = y - STATS_OVERVIEW_H - STATS_PAD

    -- ── SECTION 2: MOST PLAYED DUNGEONS ──────────────────────────────────
    local dungeonsCard = CreateStatsCard(content, y, sectionW, STATS_DUNGEON_SECTION_H)
    CreateStatsTitleBar(dungeonsCard, "Most Played Dungeons")
    self.ui.statsDungeonRows = {}
    for i = 1, MAX_STATS_DUNGEON_ROWS do
        self.ui.statsDungeonRows[i] = CreateStatsDungeonRow(dungeonsCard, i, sectionW)
    end

    y = y - STATS_DUNGEON_SECTION_H - STATS_PAD

    -- ── SECTION 3: TWO COLUMNS ────────────────────────────────────────────
    -- Left: Team Classes
    local classesCard = CreateFrame("Frame", nil, content)
    classesCard:SetPoint("TOPLEFT", STATS_PAD, y)
    classesCard:SetSize(leftColW, STATS_TWOCOL_H)
    self:ApplySurface(classesCard, COLORS.sectionBG, COLORS.surface, COLORS.accentSoft)
    ClipChildren(classesCard)
    CreateStatsTitleBar(classesCard, "Team Classes")
    self.ui.statsClassRows = {}
    for i = 1, MAX_STATS_CLASS_ROWS do
        local row = CreateFrame("Frame", nil, classesCard)
        local rowY = -((i - 1) * STATS_CLASS_ROW_H + STATS_SECTION_TITLE_H)
        row:SetPoint("TOPLEFT", 0, rowY)
        row:SetSize(leftColW, STATS_CLASS_ROW_H)
        row:Hide()
        if i % 2 == 0 then
            local bg = row:CreateTexture(nil, "BACKGROUND")
            bg:SetAllPoints()
            bg:SetTexture(WHITE_TEXTURE)
            bg:SetVertexColor(0.07, 0.07, 0.07, 1)
        end
        row.Dot = row:CreateTexture(nil, "ARTWORK")
        row.Dot:SetTexture(WHITE_TEXTURE)
        row.Dot:SetSize(9, 9)
        row.Dot:SetPoint("LEFT", 16, 0)
        row.Name = CreateFont(row, 11, COLORS.text)
        row.Name:SetPoint("LEFT", row.Dot, "RIGHT", 8, 0)
        row.Name:SetWidth(130)
        row.Count = CreateFont(row, 11, COLORS.accent, "RIGHT")
        row.Count:SetPoint("RIGHT", -16, 0)
        self.ui.statsClassRows[i] = row
    end

    -- Right: Avg Completion Time (TOPLEFT anchor from left col edge, explicit size)
    local avgTimeCard = CreateFrame("Frame", nil, content)
    avgTimeCard:SetPoint("TOPLEFT", STATS_PAD + leftColW + STATS_PAD, y)
    avgTimeCard:SetSize(rightColW, STATS_TWOCOL_H)
    self:ApplySurface(avgTimeCard, COLORS.sectionBG, COLORS.surface, COLORS.accentSoft)
    ClipChildren(avgTimeCard)
    CreateStatsTitleBar(avgTimeCard, "Avg Completion Time")
    self.ui.statsAvgTimeRows = {}
    for i = 1, MAX_STATS_DUNGEON_ROWS do
        local row = CreateFrame("Frame", nil, avgTimeCard)
        local rowY = -((i - 1) * STATS_DUNGEON_ROW_H + STATS_SECTION_TITLE_H)
        row:SetPoint("TOPLEFT", 0, rowY)
        row:SetSize(rightColW, STATS_DUNGEON_ROW_H)
        row:Hide()
        if i % 2 == 0 then
            local bg = row:CreateTexture(nil, "BACKGROUND")
            bg:SetAllPoints()
            bg:SetTexture(WHITE_TEXTURE)
            bg:SetVertexColor(0.07, 0.07, 0.07, 1)
        end
        row.Name = CreateFont(row, 11, COLORS.text)
        row.Name:SetPoint("LEFT", 16, 0)
        row.Name:SetWidth(200)
        row.Time = CreateFont(row, 12, COLORS.accent, "RIGHT")
        row.Time:SetPoint("RIGHT", -16, 0)
        self.ui.statsAvgTimeRows[i] = row
    end

    y = y - STATS_TWOCOL_H - STATS_PAD

    -- ── SECTION 4: MOST PLAYED WITH ───────────────────────────────────────
    local teammatesCard = CreateStatsCard(content, y, sectionW, STATS_TEAMMATE_SECTION_H)
    CreateStatsTitleBar(teammatesCard, "Most Played With")
    self.ui.statsTeammateRows = {}
    for i = 1, MAX_STATS_TEAMMATE_ROWS do
        local row = CreateFrame("Frame", nil, teammatesCard)
        local rowY = -((i - 1) * STATS_TEAMMATE_ROW_H + STATS_SECTION_TITLE_H)
        row:SetPoint("TOPLEFT", 0, rowY)
        row:SetSize(sectionW, STATS_TEAMMATE_ROW_H)
        row:Hide()
        if i % 2 == 0 then
            local bg = row:CreateTexture(nil, "BACKGROUND")
            bg:SetAllPoints()
            bg:SetTexture(WHITE_TEXTURE)
            bg:SetVertexColor(0.07, 0.07, 0.07, 1)
        end
        local rankBg = CreateFrame("Frame", nil, row)
        rankBg:SetSize(22, 22)
        rankBg:SetPoint("LEFT", 14, 0)
        MythicTools:ApplySurface(rankBg, COLORS.frameBG, COLORS.surface, nil)
        row.Rank = CreateFont(rankBg, 9, COLORS.subdued, "CENTER")
        row.Rank:SetAllPoints()
        row.Rank:SetText(tostring(i))
        row.Dot = row:CreateTexture(nil, "ARTWORK")
        row.Dot:SetTexture(WHITE_TEXTURE)
        row.Dot:SetSize(10, 10)
        row.Dot:SetPoint("LEFT", rankBg, "RIGHT", 10, 0)
        row.Name = CreateFont(row, 12, COLORS.text)
        row.Name:SetPoint("LEFT", row.Dot, "RIGHT", 8, 0)
        row.Name:SetWidth(200)
        row.Class = CreateFont(row, 10, COLORS.subdued)
        row.Class:SetPoint("LEFT", row.Name, "RIGHT", 10, 0)
        row.Class:SetWidth(110)
        row.Runs = CreateFont(row, 12, COLORS.accent, "RIGHT")
        row.Runs:SetPoint("RIGHT", -16, 0)
        self.ui.statsTeammateRows[i] = row
    end

    return page
end

function MythicTools:RefreshStatsView()
    if not (self.ui and self.ui.statsContent) then return end
    if not (self.ui.pages and self.ui.pages.Stats and self.ui.pages.Stats:IsShown()) then return end

    local data = self:ComputeStatsData(self.db.ui.statsFilters)

    -- Overview
    local cards = self.ui.statsOverviewCards
    if cards then
        local function sv(i, val) if cards[i] then cards[i].Value:SetText(val) end end
        sv(1, tostring(data.total))
        sv(2, data.total > 0 and string.format("%.1f%%", data.timedPct) or "--")
        sv(3, data.avgLevel > 0 and string.format("%.1f", data.avgLevel) or "--")
        sv(4, data.bestTimed > 0 and ("+%d"):format(data.bestTimed) or "--")
        sv(5, FormatTotalTime(data.totalTimeMS))
        sv(6, tostring(data.totalDeaths))
    end

    -- Dungeon rows
    local maxDungCount = (data.dungeons[1] and data.dungeons[1].count) or 1
    for i, row in ipairs(self.ui.statsDungeonRows or {}) do
        local d = data.dungeons[i]
        if d then
            row.Name:SetText(d.name)
            row.Count:SetText(tostring(d.count))
            row.Status:SetText(("T:%d  OT:%d  Ab:%d"):format(d.timed, d.overtime, d.abandoned))
            UpdateDungeonRowBar(row, d, maxDungCount)
            row:Show()
        else
            row:Hide()
        end
    end

    -- Class rows
    for i, row in ipairs(self.ui.statsClassRows or {}) do
        local c = data.classes[i]
        if c then
            local localName = (LOCALIZED_CLASS_NAMES_MALE and LOCALIZED_CLASS_NAMES_MALE[c.classFilename]) or c.classFilename or "?"
            local cc = RAID_CLASS_COLORS and RAID_CLASS_COLORS[c.classFilename]
            if cc then
                row.Dot:SetVertexColor(cc.r, cc.g, cc.b, 1)
                SetTextColor(row.Name, {cc.r, cc.g, cc.b, 1})
            else
                row.Dot:SetVertexColor(0.7, 0.7, 0.7, 1)
                SetTextColor(row.Name, COLORS.text)
            end
            row.Name:SetText(localName)
            row.Count:SetText(tostring(c.count))
            row:Show()
        else
            row:Hide()
        end
    end

    -- Avg time rows (same dungeon order)
    for i, row in ipairs(self.ui.statsAvgTimeRows or {}) do
        local d = data.dungeons[i]
        if d then
            row.Name:SetText(d.name)
            row.Time:SetText(d.avgTimeMS > 0 and self:FormatDurationMS(d.avgTimeMS) or "--")
            row:Show()
        else
            row:Hide()
        end
    end

    -- Teammate rows
    for i, row in ipairs(self.ui.statsTeammateRows or {}) do
        local t = data.teammates[i]
        if t then
            local cc = t.classFilename and RAID_CLASS_COLORS and RAID_CLASS_COLORS[t.classFilename]
            if cc then
                row.Dot:SetVertexColor(cc.r, cc.g, cc.b, 1)
            else
                row.Dot:SetVertexColor(0.6, 0.6, 0.6, 1)
            end
            row.Name:SetText(t.name)
            local localClass = (t.classFilename and LOCALIZED_CLASS_NAMES_MALE and LOCALIZED_CLASS_NAMES_MALE[t.classFilename]) or ""
            row.Class:SetText(localClass)
            row.Runs:SetText(("%d runs"):format(t.count))
            row:Show()
        else
            row:Hide()
        end
    end

    if self.ui.statsScrollFrame then self.ui.statsScrollFrame:SetVerticalScroll(0) end
    if self.ui.statsScrollBar then self.ui.statsScrollBar:SetValue(0) end
end

