local _, ns = ...
local L = ns.L or {}

local PveView = {}
ns.UIPveView = PveView

local function formatElapsed(seconds)
    seconds = math.max(0, math.floor(seconds or 0))

    local days = math.floor(seconds / 86400)
    local hours = math.floor((seconds % 86400) / 3600)
    local minutes = math.floor((seconds % 3600) / 60)

    if days > 0 then
        return string.format(L.TIME_DAY_HOUR or "%d d %d h", days, hours)
    end

    if hours > 0 then
        return string.format(L.TIME_HOUR_MIN or "%d h %d m", hours, minutes)
    end

    return string.format(L.TIME_MIN or "%d m", minutes)
end

local function getWeeklyResetSeconds()
    if type(ns.GetWeeklyResetSeconds) == "function" then
        return ns:GetWeeklyResetSeconds()
    end

    return 0
end

local function getDailyResetSeconds()
    if type(ns.GetDailyResetSeconds) == "function" then
        return ns:GetDailyResetSeconds()
    end

    return 0
end

local function fixMojibake(text)
    if type(text) ~= "string" then
        return text
    end

    local fixed = text
    fixed = fixed:gsub("\195\131\194\164", "\195\164")
    fixed = fixed:gsub("\195\131\194\182", "\195\182")
    fixed = fixed:gsub("\195\131\194\188", "\195\188")
    fixed = fixed:gsub("\195\131\226\128\158", "\195\132")
    fixed = fixed:gsub("\195\131\226\128\147", "\195\150")
    fixed = fixed:gsub("\195\131\197\147", "\195\156")
    fixed = fixed:gsub("\195\131\197\184", "\195\159")
    return fixed
end

local function normalizeEventLabel(entry)
    local label = fixMojibake((entry and entry.label) or "")
    local key = entry and entry.key or ""

    if key == "spark" then
        return L.PVE_WEEKLY_SPARK_LABEL or "Unity Against the Void (Lady Liadrin)"
    end
    if key == "soiree" or label == "Runestone / Soiree" then
        return L.PVE_EVENTS_ROW_RUNESTONES or "Fortify the Runestones"
    end
    if key == "abundance" or label == "Abundance" or label == "Offerings in Abundance" then
        return L.PVE_EVENTS_ROW_ABUNDANT_OFFERINGS or "Abundant Offerings"
    end
    if key == "stormarion" or label == "Stormarion Assault" or label == "Storm Assault" then
        return L.PVE_EVENTS_ROW_STORMARION_ASSAULT or "Stormarion Assault"
    end
    if key == "haranir" or label == "Lost Legends" then
        return L.PVE_EVENTS_ROW_LOST_LEGENDS or "Lost Legends"
    end

    return label
end

local function normalizeWorldLabel(entry)
    local label = fixMojibake((entry and entry.label) or "")
    local key = entry and entry.key or ""

    if key == "world_boss_weekly" then
        return L.PVE_WORLD_ROW_WORLD_BOSS or "World Boss"
    end
    if key == "special_assignments" and (label == "" or label == "Special Assignments" or label == "Spezialauftr\195\164ge") then
        return L.PVE_WORLD_ROW_SPECIAL_ASSIGNMENTS or "Special Assignments"
    end
    if key == "rotating_world_weekly" and (label == "" or label == "Weekly Dungeon" or label == "Dungeon") then
        return L.PVE_WEEKLY_ROW_DUNGEON or "Weekly Dungeon"
    end

    return label
end

local function countCompleted(entries)
    local completed = 0

    for _, row in ipairs(entries or {}) do
        local entry = row and row.entry
        if entry and (entry.status == "complete" or entry.completed) then
            completed = completed + 1
        end
    end

    return completed
end

function PveView.BuildWeeklyListView(character)
    local sparkEntry = ns:GetLiveSparkWeeklyState(character, nil) or {
        label = L.PVE_WEEKLY_SPARK_LABEL or "Unity Against the Void (Lady Liadrin)",
        status = "missing",
        seen = false,
        completed = false,
        text = L.STATUS_MISSING or "Accept",
        tooltipTitle = L.PVE_WEEKLY_SPARK_LABEL or "Unity Against the Void (Lady Liadrin)",
        tooltipLines = { L.PVE_WEEKLY_SPARK_ACCEPT_HINT or "This quest can be accepted from Lady Liadrin in Silvermoon." },
    }
    local dungeonEntry = ns:GetLiveRotatingDungeonWeeklyState(character, nil) or {
        label = L.PVE_WEEKLY_ROW_DUNGEON or "Weekly Dungeon",
        status = "missing",
        seen = false,
        completed = false,
        text = L.STATUS_MISSING or "Accept",
        tooltipTitle = L.PVE_WEEKLY_ROW_DUNGEON or "Weekly Dungeon",
        tooltipLines = { L.PVE_WEEKLY_DUNGEON_ACCEPT_HINT or "This quest can be accepted from Halduron in Silvermoon." },
    }
    local aethasEntry = ns:GetLiveAethasWeeklyState(character, nil) or {
        label = L.PVE_WEEKLY_ROW_AETHAS or "Rotating (Archmage Aethas)",
        status = "missing",
        seen = false,
        completed = false,
        text = L.STATUS_MISSING or "Accept",
        tooltipTitle = L.PVE_WEEKLY_ROW_AETHAS or "Rotating (Archmage Aethas)",
        tooltipLines = { L.PVE_WEEKLY_AETHAS_ACCEPT_HINT or "This quest can be accepted from Archmage Aethas in Silvermoon." },
    }
    local housingEntry = ns:GetLiveHousingWeeklyState(character, nil) or {
        label = L.PVE_WEEKLY_ROW_HOUSING or "Housing Weekly",
        status = "missing",
        seen = false,
        completed = false,
        text = L.STATUS_MISSING or "Accept",
        tooltipTitle = L.PVE_WEEKLY_ROW_HOUSING or "Housing Weekly",
        tooltipLines = { L.PVE_WEEKLY_HOUSING_ACCEPT_HINT or "This quest can be accepted from Vaeli in Silvermoon." },
    }
    local rows = {
        {
            entry = sparkEntry,
            label = L.PVE_WEEKLY_SPARK_LABEL or "Unity Against the Void (Lady Liadrin)",
        },
        {
            entry = dungeonEntry,
            label = dungeonEntry.label or (L.PVE_WEEKLY_ROW_DUNGEON or "Weekly Dungeon"),
        },
        {
            entry = aethasEntry,
            label = aethasEntry.label or (L.PVE_WEEKLY_ROW_AETHAS or "Rotating (Archmage Aethas)"),
        },
        {
            entry = housingEntry,
            label = housingEntry.label or (L.PVE_WEEKLY_ROW_HOUSING or "Housing Weekly"),
        },
    }
    local completed = countCompleted(rows)

    return {
        title = L.PVE_WEEKLY_TITLE or "Weekly PvE Goals",
        subtitle = L.PVE_WEEKLY_SUBTITLE or "Core weekly quests and event objectives for the selected character.",
        summary1 = string.format("%s  %d/%d", L.PVE_WEEKLY_PROGRESS or "Progress", completed, #rows),
        summary2 = string.format("%s  %s", L.LABEL_RESET or "Reset", formatElapsed(getWeeklyResetSeconds())),
        summary3 = "",
        rows = rows,
    }
end

function PveView.BuildPvpWeeklyListView(character)
    local weeklyEntriesRaw = ns:GetLivePvpWeeklyState(character, nil) or {}
    local rows = {}

    for _, entry in ipairs(weeklyEntriesRaw) do
        rows[#rows + 1] = {
            entry = entry,
            label = entry and entry.label or "",
        }
    end

    return {
        title = L.PVP_WEEKLY_TITLE or "Weekly PvP Goals",
        subtitle = L.PVP_WEEKLY_SUBTITLE or "Weekly PvP quests from Zerella in Silvermoon for the selected character.",
        summary1 = string.format("%s  %d/%d", L.PVP_WEEKLY_PROGRESS or L.PVE_WEEKLY_PROGRESS or "Progress", countCompleted(rows), #rows),
        summary2 = string.format("%s  %s", L.LABEL_RESET or "Reset", formatElapsed(getWeeklyResetSeconds())),
        summary3 = L.PVP_WEEKLY_GIVER_SHORT or "Zerella / Silvermoon",
        rows = rows,
    }
end

function PveView.BuildProfessionWeeklyListView(character)
    local professionState = ns:GetLiveProfessionWeeklyState(character, nil) or {}
    local professionRows = professionState.rows or {}
    local summary = professionState.summary or {}
    local rows = {}
    local darkmoonActive = ns.IsDarkmoonFaireActive and ns:IsDarkmoonFaireActive() or false

    for _, entry in ipairs(professionRows) do
        rows[#rows + 1] = {
            entry = entry,
            label = entry and entry.label or "",
        }
    end

    local knowledgeState = ns:GetLiveProfessionKnowledgeState(character, nil) or {}

    return {
        title = L.SUBTAB_SYSTEMS_PROFESSIONS or "Professions",
        subtitle = L.PROFESSIONS_SUBTITLE_WITH_DARKMOON or L.PROFESSIONS_SUBTITLE or "Midnight profession weeklies and Darkmoon Faire profession quests for the selected character.",
        summary1 = string.format("%s  %s", L.PROFESSIONS_PROGRESS or L.PVE_WEEKLY_PROGRESS or "Progress", summary.text or "0/0"),
        summary2 = string.format("%s  %s", L.LABEL_RESET or "Reset", formatElapsed(getWeeklyResetSeconds())),
        summary3 = darkmoonActive and (L.PROFESSIONS_DARKMOON_HINT or "Darkmoon: monthly") or "",
        rows = rows,
        knowledgeEntries = knowledgeState.professions or {},
    }
end

function PveView.BuildDelvesListView(character, snapshot)
    local delveState = ns:GetLiveDelvesState(character, snapshot and snapshot.delves) or {}
    local summary = delveState.summary or {}
    local rows = {}

    for _, entry in ipairs(delveState.rows or {}) do
        if entry then
            rows[#rows + 1] = {
                entry = entry,
                label = fixMojibake(entry.label or entry.key or ""),
            }
        end
    end

    return {
        title = L.SUBTAB_PVE_DELVES or "Delves",
        subtitle = L.PVE_DELVES_SUBTITLE or "Delve systems and weekly caps for the selected character.",
        summary1 = string.format("%s  %s", L.LABEL_PROGRESS or "Progress", summary.text or "--"),
        summary2 = string.format("%s  %s", L.LABEL_RESET or "Reset", formatElapsed(getWeeklyResetSeconds())),
        summary3 = "",
        rows = rows,
    }
end

function PveView.BuildEventsListView(character, snapshot)
    local weekly = ns:GetLiveWorldWeeklyState(character, snapshot and snapshot.weeklyOverview) or {}
    local eventRows = weekly.events or {}
    local summary = weekly.eventSummary or {}
    local rows = {}

    for _, entry in ipairs(eventRows) do
        if entry then
            rows[#rows + 1] = {
                entry = entry,
                label = normalizeEventLabel(entry),
            }
        end
    end

    return {
        title = L.SUBTAB_PVE_EVENTS or "Events",
        subtitle = L.PVE_EVENTS_SUBTITLE or "Midnight events for the selected character.",
        summary1 = string.format("%s  %s", L.LABEL_PROGRESS or "Progress", summary.text or "--"),
        summary2 = string.format("%s  %s", L.LABEL_RESET or "Reset", formatElapsed(getWeeklyResetSeconds())),
        summary3 = "",
        rows = rows,
    }
end

function PveView.BuildDarkmoonListView(character)
    local state = ns.GetLiveDarkmoonFaireState and ns:GetLiveDarkmoonFaireState(character, nil) or {}
    local rows = {}

    for _, entry in ipairs(state.rows or {}) do
        rows[#rows + 1] = {
            entry = entry,
            label = fixMojibake(entry and entry.label or ""),
        }
    end

    local summary = state.summary or {}
    local active = state.active == true

    return {
        title = L.SUBTAB_PVE_DARKMOON or "Darkmoon",
        subtitle = active
            and (L.PVE_DARKMOON_SUBTITLE or "Darkmoon Faire dailies, races, pet battles, and artifact turn-ins.")
            or (L.PVE_DARKMOON_INACTIVE_SUBTITLE or "Darkmoon Faire is not active."),
        summary1 = string.format("%s  %s", L.LABEL_PROGRESS or "Progress", summary.text or "0/0"),
        summary2 = active and string.format("%s  %s", L.DAILY_RESET or "Daily reset", formatElapsed(getDailyResetSeconds())) or "",
        summary3 = active and (L.PVE_DARKMOON_MONTHLY_SUMMARY or "Faire quests: monthly") or "",
        rows = rows,
        scrollRows = true,
        columnCount = 1,
    }
end

function PveView.BuildWorldListView(character, snapshot)
    local weekly = ns:GetLiveWorldWeeklyState(character, snapshot and snapshot.weeklyOverview) or {}
    local worldRows = weekly.worldRows or {}
    local summary = weekly.worldSummary or {}
    local keyCurrency = weekly.keyCurrency or {}
    local dundunCurrency = weekly.dundunCurrency or {}
    local rows = {}

    for _, entry in ipairs(worldRows) do
        if entry then
            rows[#rows + 1] = {
                entry = entry,
                label = normalizeWorldLabel(entry),
            }
        end
    end

    rows[#rows + 1] = {
        entry = {
            key = "world_key_shards",
            status = keyCurrency.capped and "complete" or "open",
            text = keyCurrency.text or "--",
            tooltipTitle = keyCurrency.tooltipTitle or (L.PVE_WORLD_ROW_KEY_SHARDS or "Coffer Key Shards"),
            tooltipLines = keyCurrency.tooltipLines or { L.PVE_WORLD_KEY_SHARDS_HINT or "Tracks the weekly cap for Coffer Key Shards." },
        },
        label = L.PVE_WORLD_ROW_KEY_SHARDS or "Coffer Key Shards",
    }
    rows[#rows + 1] = {
        entry = {
            key = "world_dundun_shards",
            status = dundunCurrency.capped and "complete" or "open",
            text = dundunCurrency.text or "0/8",
            tooltipTitle = dundunCurrency.tooltipTitle or (L.PVE_WORLD_ROW_DUNDUN_SHARDS or "Shard of Dundun"),
            tooltipLines = dundunCurrency.tooltipLines or { L.PVE_WORLD_DUNDUN_HINT or "Tracks the weekly cap for Shards of Dundun." },
        },
        label = L.PVE_WORLD_ROW_DUNDUN_SHARDS or "Shard of Dundun",
    }

    return {
        title = L.SUBTAB_PVE_WORLD or "World",
        subtitle = L.PVE_WORLD_SUBTITLE or "World weeklies including boss and currency caps.",
        summary1 = string.format("%s  %s", L.LABEL_PROGRESS or "Progress", summary.text or "--"),
        summary2 = string.format("%s  %s", L.LABEL_RESET or "Reset", formatElapsed(getWeeklyResetSeconds())),
        summary3 = "",
        rows = rows,
    }
end

function PveView.BuildDailyListView(character, snapshot)
    local dailyState = ns:GetLiveDailyPveState(character, snapshot and snapshot.weeklyOverview) or {}
    local dailyBountiful = dailyState.dailyBountiful or {}
    local dailyWanted = dailyState.dailyWanted or {}
    local dailyDecorDuel = dailyState.dailyDecorDuel or {}
    local dailySummary = dailyState.summary or {}
    local cap = tonumber(dailyBountiful.cap) or 4
    local done = math.max(0, tonumber(dailyBountiful.completed) or 0)
    local rows = {}

    rows[#rows + 1] = {
        entry = {
            key = "daily_bountiful",
            status = dailyBountiful.status or ((done >= cap and cap > 0) and "complete" or "open"),
            text = dailyBountiful.text or string.format("%d/%d", done, cap),
            tooltipTitle = dailyBountiful.tooltipTitle or (L.PVE_DAILY_ROW_BOUNTIFUL or "Bountiful Delves"),
            tooltipLines = dailyBountiful.tooltipLines or { L.PVE_DAILY_BOUNTIFUL_HINT or "Tracks completed bountiful delves for today." },
        },
        label = L.PVE_DAILY_ROW_BOUNTIFUL or "Bountiful Delves",
    }

    local wantedLabel = fixMojibake(dailyWanted.label or (L.DAILY_WANTED_HARANDAR or "Wanted - Harandar"))
    rows[#rows + 1] = {
        entry = dailyWanted.key and dailyWanted or {
            key = "daily_wanted_harandar",
            status = "locked",
            text = L.DAILY_STATUS_UNAVAILABLE or "Unavailable",
            tooltipTitle = wantedLabel,
            tooltipLines = { L.DAILY_WANTED_HARANDAR_UNAVAILABLE_HINT or "This daily is not available today." },
        },
        label = wantedLabel,
    }

    local decorDuelLabel = fixMojibake(dailyDecorDuel.label or (L.DAILY_DECOR_DUEL or "Decor Duel"))
    rows[#rows + 1] = {
        entry = dailyDecorDuel.key and dailyDecorDuel or {
            key = "daily_decor_duel",
            status = "locked",
            text = L.DAILY_STATUS_UNAVAILABLE or "Unavailable",
            tooltipTitle = decorDuelLabel,
            tooltipLines = { L.DAILY_DECOR_DUEL_UNAVAILABLE_HINT or "This daily is not available today." },
        },
        label = decorDuelLabel,
    }

    return {
        title = L.SUBTAB_PVE_DAILY or "Daily",
        subtitle = L.PVE_DAILY_SUBTITLE or "Daily objectives for the selected character.",
        summary1 = string.format("%s  %s", L.LABEL_PROGRESS or "Progress", dailySummary.text or "0/3"),
        summary2 = string.format("%s  %s", L.DAILY_RESET or "Daily reset", formatElapsed(getDailyResetSeconds())),
        summary3 = "",
        rows = rows,
    }
end

function PveView.BuildOtherListView(_, snapshot)
    local weekly = snapshot and snapshot.weeklyOverview or {}
    local otherRows = weekly.otherRows or {}
    local summary = weekly.otherSummary or {}
    local rows = {}

    for _, entry in ipairs(otherRows) do
        if entry then
            rows[#rows + 1] = {
                entry = entry,
                label = fixMojibake(entry.label or entry.key or ""),
            }
        end
    end

    return {
        title = L.SUBTAB_PVE_OTHER or "Other",
        subtitle = L.CONTENT_SUBTITLE or "This is a placeholder content area for the selected section.",
        summary1 = string.format("%s  %s", L.LABEL_PROGRESS or "Progress", summary.text or "--"),
        summary2 = string.format("%s  %s", L.LABEL_RESET or "Reset", formatElapsed(getWeeklyResetSeconds())),
        summary3 = "",
        rows = rows,
    }
end

function PveView.BuildRaresView(character)
    local state = ns:GetLiveMidnightRareState(character, nil) or {}
    local selectedZoneKey = ns.GetSelectedMidnightRareZoneKey and ns:GetSelectedMidnightRareZoneKey() or nil
    local selectedZone = nil

    for _, zone in ipairs(state.zones or {}) do
        if zone.key == selectedZoneKey then
            selectedZone = zone
            break
        end
    end

    if not selectedZone then
        selectedZone = state.zones and state.zones[1] or nil
        selectedZoneKey = selectedZone and selectedZone.key or selectedZoneKey
    end

    return {
        title = L.PVE_RARES_TITLE or "Rare Mobs",
        subtitle = L.PVE_RARES_SUBTITLE or "Daily Midnight rare kills and mount collection by zone.",
        selectedZoneKey = selectedZoneKey,
        selectedZone = selectedZone,
        zones = state.zones or {},
        summary1 = string.format("%s  %s", L.LABEL_PROGRESS or "Progress", state.text or "0/0"),
        summary2 = string.format("%s  %s", L.PVE_RARES_MOUNTS or "Mounts", state.mountText or "0/0"),
        summary3 = string.format("%s  %s", L.DAILY_RESET or "Daily reset", formatElapsed(getDailyResetSeconds())),
        state = state,
    }
end

function PveView.BuildPreyView(character, snapshot)
    local weekly = snapshot and snapshot.weeklyOverview or {}
    local prey = ns:GetLivePreyState(character, weekly.prey or {}) or {}
    local totalCap = tonumber(prey.totalCap) or 12
    local difficultyCap = tonumber(prey.difficultyCap) or 4
    local total = tonumber(prey.total) or 0
    local unlockedCount = tonumber(prey.unlockedCount) or math.floor(totalCap / math.max(1, difficultyCap)) or 1
    local weeklyQuest = ns:GetLivePreyWeeklyQuestState(character, weekly.prey and weekly.prey.weeklyQuest or {}) or {}
    local preferredQuest = ns:GetLivePreyPreferredQuestState(character, weekly.prey and weekly.prey.preferredQuest or {}) or {}
    local totalThresholds = {}

    for index = 1, math.max(1, unlockedCount) do
        totalThresholds[#totalThresholds + 1] = index * difficultyCap
    end

    local subtitle = L.PVE_PREY_SUBTITLE or "Defeated prey targets by difficulty, plus the linked weekly quest."
    if prey.activeMapName and prey.activeMapName ~= "" then
        subtitle = string.format(
            L.PVE_PREY_SUBTITLE_ACTIVE or "Defeated prey targets by difficulty. Active prey: %s.",
            prey.activeMapName
        )
    end

    local weeklyLabel = (weeklyQuest.tooltipTitle and weeklyQuest.tooltipTitle ~= "" and weeklyQuest.tooltipTitle)
        or (weeklyQuest.label or "")
    if weeklyLabel == "" or weeklyLabel == "Weekly" or weeklyLabel == "Woechentlich" or weeklyLabel == "W\195\182chentlich" then
        weeklyLabel = L.PVE_PREY_WEEKLY_NAME or "A Nightmarish Task"
    end

    local difficulties = prey.difficulties or {}

    return {
        title = L.PVE_PREY_TITLE or "Prey",
        subtitle = subtitle,
        totalLabel = L.WEEKLY_PREY_TOTAL or "Defeated Prey Targets",
        totalValue = string.format("%d/%d", total, totalCap),
        totalRatio = totalCap > 0 and (total / totalCap) or 0,
        totalCap = totalCap,
        totalThresholds = totalThresholds,
        difficultyCap = difficultyCap,
        difficulties = {
            normal = {
                label = L.WEEKLY_PREY_NORMAL or "Normal",
                entry = difficulties.normal or {},
                color = { 0.58, 0.82, 0.72 },
            },
            hard = {
                label = L.WEEKLY_PREY_HARD or "Hard",
                entry = difficulties.hard or {},
                color = { 0.82, 0.66, 0.34 },
            },
            nightmare = {
                label = L.WEEKLY_PREY_NIGHTMARE or "Nightmare",
                entry = difficulties.nightmare or {},
                color = { 0.82, 0.34, 0.38 },
            },
        },
        weeklyQuest = weeklyQuest,
        weeklyLabel = weeklyLabel,
        preferredQuest = preferredQuest,
        preferredLabel = L.PVE_PREY_PREFERRED_NAME or "Preferred Prey",
    }
end
