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

local DATA = ns.Data or {}
local MIDNIGHT_WORLD_BOSS_POOL = DATA.MIDNIGHT_WORLD_BOSS_POOL or {}
local MIDNIGHT_WORLD_BOSS_NAME_PATTERNS = DATA.MIDNIGHT_WORLD_BOSS_NAME_PATTERNS or {}
local SPECIAL_ASSIGNMENT_ENTRIES = DATA.SPECIAL_ASSIGNMENT_ENTRIES or {}
local WORLD_KEY_SHARD_CURRENCY_IDS = DATA.WORLD_KEY_SHARD_CURRENCY_IDS or {}
local WORLD_DUNDUN_SHARD_CURRENCY_IDS = DATA.WORLD_DUNDUN_SHARD_CURRENCY_IDS or {}

local WorldWeeklyWorldRows = {}
ns.WorldWeeklyWorldRows = WorldWeeklyWorldRows

local Util = ns.Util or {}
local safeCopyTable = Util.SafeCopyTable
local stringContainsAnyPattern = Util.StringContainsAnyPattern

local Quest = ns.Quest or {}
local isQuestCompleted = Quest.IsQuestCompleted
local isQuestActive = Quest.IsQuestActive
local getQuestObjectiveLines = Quest.GetQuestObjectiveLines
local isQuestTurnInReady = Quest.IsQuestTurnInReady
local getQuestObjectiveProgressText = Quest.GetQuestObjectiveProgressText
local getQuestTitle = Quest.GetQuestTitle

local WeeklyCurrency = ns.WeeklyCurrency or {}
local buildWeeklyCurrencyState = WeeklyCurrency.BuildWeeklyCurrencyState

local function getActiveQuestStatusText(questID, readyToTurnIn, turnInText, openFallback)
    if readyToTurnIn then
        return turnInText or (L.STATUS_TURNIN or "Turn in")
    end

    if type(getQuestObjectiveProgressText) == "function" then
        local progressText = getQuestObjectiveProgressText(questID)
        if type(progressText) == "string" and progressText ~= "" then
            return progressText
        end
    end

    return openFallback or (L.STATUS_OPEN or "Accepted")
end

local function getMatchedSavedWorldBossName()
    if type(GetNumSavedWorldBosses) ~= "function" or type(GetSavedWorldBossInfo) ~= "function" then
        return nil
    end

    local count = GetNumSavedWorldBosses() or 0
    for index = 1, count do
        local name = GetSavedWorldBossInfo(index)
        if type(name) == "string" and name ~= "" and stringContainsAnyPattern(name, MIDNIGHT_WORLD_BOSS_NAME_PATTERNS) then
            return name
        end
    end

    return nil
end

local function buildWorldBossWeeklyRow()
    local label = L.PVE_WORLD_ROW_WORLD_BOSS or "World Boss"
    local activeQuestID
    local completedQuestID

    for _, questID in ipairs(MIDNIGHT_WORLD_BOSS_POOL) do
        if isQuestCompleted(questID) then
            completedQuestID = questID
            break
        end
        if not activeQuestID and isQuestActive(questID) then
            activeQuestID = questID
        end
    end

    local savedBossName = not completedQuestID and getMatchedSavedWorldBossName() or nil
    if completedQuestID or savedBossName then
        return {
            key = "world_boss_weekly",
            label = label,
            text = L.STATUS_DONE or "Done",
            status = "complete",
            seen = true,
            completed = true,
            questID = completedQuestID,
            tooltipTitle = savedBossName or label,
            tooltipLines = {
                L.PVE_WORLD_BOSS_DONE_HINT or "Already completed this week.",
            },
        }
    end

    local tooltipLines = {}
    if activeQuestID then
        tooltipLines = getQuestObjectiveLines(activeQuestID)
    end
    if #tooltipLines == 0 then
        tooltipLines[#tooltipLines + 1] = L.PVE_WORLD_BOSS_HINT
            or "Granted automatically when you engage the boss. Fly there and kill it."
    end

    local readyToTurnIn = activeQuestID and isQuestTurnInReady(activeQuestID) or false

    return {
        key = "world_boss_weekly",
        label = label,
        text = activeQuestID and getActiveQuestStatusText(activeQuestID, readyToTurnIn, nil, L.PVE_WEEKLY_OPEN or "Open")
            or (L.PVE_WEEKLY_OPEN or "Open"),
        status = readyToTurnIn and "turnin" or "open",
        seen = activeQuestID ~= nil,
        completed = false,
        questID = activeQuestID,
        turnInQuestID = readyToTurnIn and activeQuestID or nil,
        tooltipTitle = activeQuestID and getQuestTitle(activeQuestID, label) or label,
        tooltipLines = tooltipLines,
    }
end

local function buildSpecialAssignmentsWeeklyRow(fallbackEntry)
    local label = L.PVE_WORLD_ROW_SPECIAL_ASSIGNMENTS
        or (type(fallbackEntry) == "table" and fallbackEntry.label)
        or "Special Assignments"
    local completedCount = 0
    local activeCount = 0
    local activeQuestIDs = {}
    local availableTitles = {}

    for _, entry in ipairs(SPECIAL_ASSIGNMENT_ENTRIES) do
        if entry.quest and isQuestCompleted(entry.quest) then
            completedCount = completedCount + 1
        elseif (entry.quest and isQuestActive(entry.quest)) or (entry.unlockQuest and isQuestCompleted(entry.unlockQuest)) then
            activeCount = activeCount + 1
            if entry.quest and isQuestActive(entry.quest) then
                activeQuestIDs[#activeQuestIDs + 1] = entry.quest
                availableTitles[#availableTitles + 1] = getQuestTitle(entry.quest, string.format("Quest %d", entry.quest))
            elseif entry.quest then
                availableTitles[#availableTitles + 1] = getQuestTitle(entry.quest, string.format("Quest %d", entry.quest))
            end
        end
    end

    local maxCount = 2
    local count = math.min(maxCount, completedCount)
    local completed = count >= maxCount
    local seen = completed or activeCount > 0 or count > 0
    local status = completed and "complete" or (seen and "open" or "missing")
    local tooltipLines = {}

    if completed then
        tooltipLines[#tooltipLines + 1] = L.PVE_WORLD_SPECIAL_ASSIGNMENTS_DONE_HINT
            or "Both Special Assignments are completed for this week."
    else
        tooltipLines[#tooltipLines + 1] = L.PVE_WORLD_SPECIAL_ASSIGNMENTS_HINT
            or "Complete both Special Assignments available this week."

        if #availableTitles > 0 then
            tooltipLines[#tooltipLines + 1] = string.format(
                L.PVE_WORLD_SPECIAL_ASSIGNMENTS_AVAILABLE or "Currently available: %s",
                table.concat(availableTitles, ", ")
            )
        end

        for _, questID in ipairs(activeQuestIDs) do
            local objectiveLines = getQuestObjectiveLines(questID)
            for _, line in ipairs(objectiveLines) do
                if type(line) == "string" and line ~= "" then
                    tooltipLines[#tooltipLines + 1] = line
                end
            end
        end
    end

    return {
        key = "special_assignments",
        label = label,
        count = count,
        maxCount = maxCount,
        completed = completed,
        seen = seen,
        status = status,
        text = string.format("%d/%d", count, maxCount),
        questID = activeQuestIDs[1] or nil,
        tooltipTitle = label,
        tooltipLines = tooltipLines,
    }
end

function WorldWeeklyWorldRows.BuildRows(fallbackOverview)
    local worldRows = {}
    local insertedWorldBoss = false
    local insertedSpecialAssignments = false

    for _, entry in ipairs(type(fallbackOverview) == "table" and fallbackOverview.worldRows or {}) do
        if type(entry) == "table" then
            if entry.key == "world_boss_weekly" then
                worldRows[#worldRows + 1] = buildWorldBossWeeklyRow()
                insertedWorldBoss = true
            elseif entry.key == "special_assignments" then
                worldRows[#worldRows + 1] = buildSpecialAssignmentsWeeklyRow(entry)
                insertedSpecialAssignments = true
            else
                worldRows[#worldRows + 1] = safeCopyTable(entry)
            end
        end
    end

    if not insertedWorldBoss then
        table.insert(worldRows, 1, buildWorldBossWeeklyRow())
    end
    if not insertedSpecialAssignments then
        table.insert(worldRows, math.min(2, #worldRows + 1), buildSpecialAssignmentsWeeklyRow())
    end

    return worldRows
end

function WorldWeeklyWorldRows.BuildCurrencies()
    local keyCurrency = buildWeeklyCurrencyState(
        WORLD_KEY_SHARD_CURRENCY_IDS,
        L.PVE_WORLD_ROW_KEY_SHARDS or "Coffer Key Shards",
        600,
        L.PVE_WORLD_KEY_SHARDS_HINT or "Tracks the weekly cap for Coffer Key Shards.",
        L.PVE_WORLD_CURRENCY_OWNED or "Currently owned: %d"
    )
    local dundunCurrency = buildWeeklyCurrencyState(
        WORLD_DUNDUN_SHARD_CURRENCY_IDS,
        L.PVE_WORLD_ROW_DUNDUN_SHARDS or "Shard of Dundun",
        8,
        L.PVE_WORLD_DUNDUN_HINT or "Tracks the weekly cap for Shards of Dundun.",
        L.PVE_WORLD_CURRENCY_OWNED or "Currently owned: %d"
    )

    return keyCurrency, dundunCurrency
end

function WorldWeeklyWorldRows.BuildSummary(rows, keyCurrency, dundunCurrency)
    local completed = 0
    local total = 0

    for _, row in ipairs(rows or {}) do
        if row then
            total = total + 1
            if row.status == "complete" or row.completed == true then
                completed = completed + 1
            end
        end
    end

    total = total + 2
    if keyCurrency and keyCurrency.capped then
        completed = completed + 1
    end
    if dundunCurrency and dundunCurrency.capped then
        completed = completed + 1
    end

    return {
        completed = completed,
        open = math.max(0, total - completed),
        total = total,
        text = string.format("%d/%d", completed, total),
    }
end
