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

local DATA = ns.Data or {}
local DAILY_WANTED_HARANDAR_POOL = DATA.DAILY_WANTED_HARANDAR_POOL or {}
local DAILY_WANTED_HARANDAR_NPC = DATA.DAILY_WANTED_HARANDAR_NPC or "Shul'ka Li'tya"
local DAILY_WANTED_HARANDAR_AREA = DATA.DAILY_WANTED_HARANDAR_AREA or "Harandar"
local DAILY_WANTED_HARANDAR_WAYPOINT = DATA.DAILY_WANTED_HARANDAR_WAYPOINT or {}
local DAILY_DECOR_DUEL_QUEST_ID = DATA.DAILY_DECOR_DUEL_QUEST_ID or 93870

local DailyPveBountiful = ns.DailyPveBountiful or {}
local buildCurrentDailyBountifulState = DailyPveBountiful.BuildCurrentState

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

local function collectHarandarWantedQuestIDsFromGossip()
    local ids = {}
    local seen = {}

    local function addQuestID(questID)
        questID = tonumber(questID)
        if not questID or questID <= 0 or seen[questID] then
            return
        end

        for _, poolQuestID in ipairs(DAILY_WANTED_HARANDAR_POOL) do
            if questID == poolQuestID then
                seen[questID] = true
                ids[#ids + 1] = questID
                return
            end
        end
    end

    if C_GossipInfo and type(C_GossipInfo.GetAvailableQuests) == "function" then
        local ok, availableQuests = pcall(C_GossipInfo.GetAvailableQuests)
        if ok and type(availableQuests) == "table" then
            for _, questInfo in ipairs(availableQuests) do
                addQuestID(type(questInfo) == "table" and questInfo.questID or nil)
            end
        end
    end

    if C_GossipInfo and type(C_GossipInfo.GetActiveQuests) == "function" then
        local ok, activeQuests = pcall(C_GossipInfo.GetActiveQuests)
        if ok and type(activeQuests) == "table" then
            for _, questInfo in ipairs(activeQuests) do
                addQuestID(type(questInfo) == "table" and questInfo.questID or nil)
            end
        end
    end

    return ids
end

function ns:RememberHarandarWantedQuests(questIDs)
    if type(questIDs) ~= "table" or #questIDs == 0 then
        return false
    end

    local record = self:RefreshCurrentCharacterRecord()
    self:ClearExpiredDailyPveState(record)

    local dailyResetSeconds = math.max(0, self:GetDailyResetSeconds())
    record.dailyPve = type(record.dailyPve) == "table" and record.dailyPve or {}
    record.dailyPve.resetAt = dailyResetSeconds > 0 and (time() + dailyResetSeconds) or record.dailyPve.resetAt
    record.dailyPve.state = type(record.dailyPve.state) == "table" and record.dailyPve.state or {}

    local dailyWanted = type(record.dailyPve.state.dailyWanted) == "table" and record.dailyPve.state.dailyWanted or {}
    local discoveredIDs = type(dailyWanted.discoveredIDs) == "table" and dailyWanted.discoveredIDs or {}
    local changed = false
    local count = 0

    for _, questID in ipairs(questIDs) do
        questID = tonumber(questID)
        if questID and questID > 0 and not discoveredIDs[questID] then
            discoveredIDs[questID] = true
            changed = true
        end
    end

    for questID, isKnown in pairs(discoveredIDs) do
        if isKnown then
            count = count + 1
        else
            discoveredIDs[questID] = nil
        end
    end

    if count > (tonumber(dailyWanted.lastKnownTotal) or 0) then
        dailyWanted.lastKnownTotal = count
        changed = true
    end

    dailyWanted.discoveredIDs = discoveredIDs
    record.dailyPve.state.dailyWanted = dailyWanted

    return changed
end

local function buildDailyWantedHarandarState(stickyState)
    local completedIDs = {}
    local activeIDs = {}
    local availableIDs = {}
    local availableNames = {}
    local activeNames = {}
    local poolLookup = {}
    local visibleOnMap = {}
    local stickyIDs = {}
    local stickyCount = 0

    for _, questID in ipairs(DAILY_WANTED_HARANDAR_POOL) do
        poolLookup[questID] = true
        if isQuestCompleted(questID) then
            completedIDs[#completedIDs + 1] = questID
        elseif isQuestActive(questID) then
            activeIDs[#activeIDs + 1] = questID
        end
    end

    for _, questID in ipairs(getTaskQuestIDsOnMap(DAILY_WANTED_HARANDAR_WAYPOINT.mapIDs[1])) do
        if poolLookup[questID] then
            visibleOnMap[questID] = true
        end
    end

    if type(stickyState) == "table" and type(stickyState.discoveredIDs) == "table" then
        for questID, isKnown in pairs(stickyState.discoveredIDs) do
            questID = tonumber(questID)
            if isKnown and questID and poolLookup[questID] then
                stickyIDs[questID] = true
                stickyCount = stickyCount + 1
            end
        end
    end

    for _, questID in ipairs(DAILY_WANTED_HARANDAR_POOL) do
        if not isQuestCompleted(questID) and not isQuestActive(questID) then
            if visibleOnMap[questID] or stickyIDs[questID] or isTaskQuestActive(questID) then
                availableIDs[#availableIDs + 1] = questID
            end
        end
    end

    for _, questID in ipairs(activeIDs) do
        local questTitle = getQuestTitle(questID, string.format("Quest %d", questID))
        activeNames[#activeNames + 1] = questTitle
        availableNames[#availableNames + 1] = questTitle
    end
    if #availableNames == 0 then
        for _, questID in ipairs(availableIDs) do
            availableNames[#availableNames + 1] = getQuestTitle(questID, string.format("Quest %d", questID))
        end
    end

    local tooltipLines = {}
    local status
    local text
    local completedCount = #completedIDs
    local activeCount = #activeIDs
    local availableCount = #availableIDs
    local totalToday = completedCount + activeCount + availableCount
    totalToday = math.max(totalToday, tonumber(type(stickyState) == "table" and stickyState.lastKnownTotal) or 0, stickyCount)

    if totalToday > 1 then
        tooltipLines[#tooltipLines + 1] = string.format(
            L.DAILY_WANTED_HARANDAR_PROGRESS_COUNT or "Completed today: %d/%d",
            completedCount,
            totalToday
        )
    end

    if completedCount > 0 and completedCount >= math.max(1, totalToday) then
        status = "complete"
        text = L.DAILY_STATUS_DONE or "Done"
        tooltipLines[#tooltipLines + 1] = L.DAILY_WANTED_HARANDAR_DONE_HINT or "Completed for today."
    elseif activeCount > 0 then
        local readyToTurnIn = false
        for _, questID in ipairs(activeIDs) do
            if isQuestTurnInReady(questID) then
                readyToTurnIn = true
                break
            end
        end

        status = readyToTurnIn and "turnin" or "open"
        if totalToday > 1 then
            text = string.format("%d/%d", completedCount, totalToday)
        else
            local progressText = type(getQuestObjectiveProgressText) == "function" and getQuestObjectiveProgressText(activeIDs[1]) or nil
            text = readyToTurnIn and (L.STATUS_TURNIN or "Turn in")
                or progressText
                or (L.DAILY_STATUS_ACCEPTED or "Accepted")
        end

        if #activeNames > 0 then
            tooltipLines[#tooltipLines + 1] = string.format(
                L.DAILY_WANTED_HARANDAR_ACCEPTED_HINT or "Accepted: %s",
                table.concat(activeNames, ", ")
            )
        end

        for _, questID in ipairs(activeIDs) 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
        if #tooltipLines == 0 then
            tooltipLines[#tooltipLines + 1] = readyToTurnIn
                and (L.DAILY_WANTED_HARANDAR_TURNIN_HINT or "This quest is done and can now be turned in.")
                or (L.DAILY_WANTED_HARANDAR_PROGRESS_HINT or "This quest is active. Open your quest log to see the current objective.")
        end
    elseif availableCount > 0 then
        status = "missing"
        if totalToday > 1 then
            text = string.format("%d/%d", completedCount, totalToday)
        else
            text = L.DAILY_STATUS_ACCEPT or "Accept"
        end
        tooltipLines[#tooltipLines + 1] = string.format(
            L.DAILY_WANTED_HARANDAR_ACCEPT_HINT or "This quest can be picked up from %s in %s.",
            DAILY_WANTED_HARANDAR_NPC,
            DAILY_WANTED_HARANDAR_AREA
        )
        if #availableNames > 0 then
            tooltipLines[#tooltipLines + 1] = string.format(
                L.DAILY_WANTED_HARANDAR_AVAILABLE_HINT or "Currently available: %s",
                table.concat(availableNames, ", ")
            )
        end
    else
        status = "locked"
        text = L.DAILY_STATUS_UNAVAILABLE or "Unavailable"
        tooltipLines[#tooltipLines + 1] = L.DAILY_WANTED_HARANDAR_UNAVAILABLE_HINT or "This daily is not available today."
        tooltipLines[#tooltipLines + 1] = L.DAILY_WANTED_HARANDAR_LIMITED_HINT or "This quest is not available every day."
    end

    return {
        key = "daily_wanted_harandar",
        label = L.DAILY_WANTED_HARANDAR or "Wanted - Harandar",
        text = text,
        status = status,
        seen = totalToday > 0,
        completed = completedCount > 0 and completedCount >= math.max(1, totalToday),
        activeIDs = activeIDs,
        availableIDs = availableIDs,
        completedIDs = completedIDs,
        totalToday = totalToday,
        lastKnownTotal = totalToday,
        discoveredIDs = stickyIDs,
        tooltipTitle = L.DAILY_WANTED_HARANDAR or "Wanted - Harandar",
        tooltipLines = tooltipLines,
        waypoint = {
            mapIDs = DAILY_WANTED_HARANDAR_WAYPOINT.mapIDs,
            x = DAILY_WANTED_HARANDAR_WAYPOINT.x,
            y = DAILY_WANTED_HARANDAR_WAYPOINT.y,
            title = string.format("%s - %s", DAILY_WANTED_HARANDAR_NPC, DAILY_WANTED_HARANDAR_AREA),
        },
    }
end

local function buildDailyDecorDuelState()
    local questID = DAILY_DECOR_DUEL_QUEST_ID
    local label = L.DAILY_DECOR_DUEL or "Decor Duel"
    local questTitle = getQuestTitle(questID, label) or label
    local tooltipLines = {}

    if isQuestCompleted(questID) then
        tooltipLines[#tooltipLines + 1] = L.DAILY_DECOR_DUEL_DONE_HINT or "Completed for today."
        return {
            key = "daily_decor_duel",
            label = label,
            text = L.DAILY_STATUS_DONE or "Done",
            status = "complete",
            seen = true,
            completed = true,
            questID = questID,
            tooltipTitle = questTitle,
            tooltipLines = tooltipLines,
        }
    end

    if isQuestActive(questID) then
        local readyToTurnIn = isQuestTurnInReady(questID)
        for _, line in ipairs(getQuestObjectiveLines(questID)) do
            if type(line) == "string" and line ~= "" then
                tooltipLines[#tooltipLines + 1] = line
            end
        end
        if #tooltipLines == 0 then
            tooltipLines[#tooltipLines + 1] = readyToTurnIn
                and (L.DAILY_DECOR_DUEL_TURNIN_HINT or "This quest is done and can now be turned in.")
                or (L.DAILY_DECOR_DUEL_PROGRESS_HINT or "This quest is active. Open your quest log to see the current objective.")
        end

        return {
            key = "daily_decor_duel",
            label = label,
            text = readyToTurnIn and (L.STATUS_TURNIN or "Turn in")
                or getQuestObjectiveProgressText(questID)
                or (L.DAILY_STATUS_ACCEPTED or "Accepted"),
            status = readyToTurnIn and "turnin" or "open",
            seen = true,
            completed = false,
            questID = questID,
            turnInQuestID = readyToTurnIn and questID or nil,
            tooltipTitle = questTitle,
            tooltipLines = tooltipLines,
        }
    end

    tooltipLines[#tooltipLines + 1] = isTaskQuestActive(questID)
        and (L.DAILY_DECOR_DUEL_AVAILABLE_HINT or "This daily is currently available.")
        or (L.DAILY_DECOR_DUEL_ACCEPT_HINT or "Pick up this daily quest if you have not completed it today.")
    return {
        key = "daily_decor_duel",
        label = label,
        text = L.DAILY_STATUS_ACCEPT or "Accept",
        status = "missing",
        seen = true,
        completed = false,
        questID = questID,
        tooltipTitle = questTitle,
        tooltipLines = tooltipLines,
    }
end


function ns:CollectHarandarWantedQuestIDsFromGossip()
    return collectHarandarWantedQuestIDsFromGossip()
end

function ns:BuildCurrentDailyPveState(record)
    local stickyState = type(record) == "table"
        and type(record.dailyPve) == "table"
        and type(record.dailyPve.state) == "table"
        and record.dailyPve.state
        or nil
    local dailyBountiful = buildCurrentDailyBountifulState(stickyState and stickyState.dailyBountiful or nil, record)
    local dailyWanted = buildDailyWantedHarandarState(stickyState and stickyState.dailyWanted or nil)
    local dailyDecorDuel = buildDailyDecorDuelState()
    local completedRows = 0

    if dailyBountiful.status == "complete" then
        completedRows = completedRows + 1
    end
    if dailyWanted.status == "complete" then
        completedRows = completedRows + 1
    end
    if dailyDecorDuel.status == "complete" then
        completedRows = completedRows + 1
    end

    return {
        dailyBountiful = dailyBountiful,
        dailyWanted = dailyWanted,
        dailyDecorDuel = dailyDecorDuel,
        summary = {
            completed = completedRows,
            total = 3,
            text = string.format("%d/%d", completedRows, 3),
        },
    }
end

function ns:RefreshCurrentCharacterDailyPveData()
    local record = self:RefreshCurrentCharacterRecord()
    self:ClearExpiredDailyPveState(record)

    local state = self:BuildCurrentDailyPveState(record)
    if not state then
        return nil
    end

    local dailyResetSeconds = math.max(0, self:GetDailyResetSeconds())
    record.dailyPve = {
        resetAt = dailyResetSeconds > 0 and (time() + dailyResetSeconds) or nil,
        state = state,
    }

    return state
end

function ns:GetLiveDailyPveState(keyOrCharacter, fallbackState)
    local key = keyOrCharacter
    if type(keyOrCharacter) == "table" then
        key = keyOrCharacter.key
    end

    if self:IsCurrentCharacterKey(key) then
        local liveState = self:RefreshCurrentCharacterDailyPveData()
        if liveState then
            return liveState
        end
    end

    local storedState = self:GetStoredDailyPveState(key)
    if storedState then
        return storedState
    end

    return fallbackState
end
