GuildHelper = GuildHelper or {}

local addon = GuildHelper

addon.NeedsService = addon.NeedsService or {}

local ORDERED_NEED_KEYS = { "tanks", "healers", "melee", "ranged", "dps" }

local function cloneDeficits(source)
    return {
        tanks = tonumber(source and source.tanks) or 0,
        healers = tonumber(source and source.healers) or 0,
        melee = tonumber(source and source.melee) or 0,
        ranged = tonumber(source and source.ranged) or 0,
        dps = tonumber(source and source.dps) or 0,
    }
end

local function buildDeficitText(deficits, orderedKeys, emptyText)
    local parts = {}

    for _, key in ipairs(orderedKeys or ORDERED_NEED_KEYS) do
        local value = tonumber(deficits and deficits[key]) or 0

        if value > 0 then
            parts[#parts + 1] = string.format("%s: %d", key, value)
        end
    end

    if #parts == 0 then
        return emptyText or "No shortages detected."
    end

    return table.concat(parts, ", ")
end

local function getDeficitTotal(deficits)
    return (tonumber(deficits and deficits.tanks) or 0)
        + (tonumber(deficits and deficits.healers) or 0)
        + (tonumber(deficits and deficits.dps) or 0)
end

local function shouldCountForNeeds(member, onlineOnly)
    if member.deleted or member.leftGuild then
        return false
    end

    if onlineOnly and not member.online then
        return false
    end

    return true
end

function addon.NeedsService:GetRoleCounts(onlineOnly)
    local counts = {
        tanks = 0,
        healers = 0,
        dps = 0,
        melee = 0,
        ranged = 0,
    }

    for _, member in ipairs(addon.RosterService:ListVisibleMembers()) do
        if shouldCountForNeeds(member, onlineOnly) then
            if member.primaryRole == "tank" then
                counts.tanks = counts.tanks + 1
            elseif member.primaryRole == "healer" then
                counts.healers = counts.healers + 1
            else
                counts.dps = counts.dps + 1
            end

            if member.meleeOrRanged == "melee" then
                counts.melee = counts.melee + 1
            elseif member.meleeOrRanged == "ranged" then
                counts.ranged = counts.ranged + 1
            end
        end
    end

    return counts
end

function addon.NeedsService:GetNeedsSnapshot(activityType, onlineOnly)
    local rules = addon.Store:GetGuild().needs.rules[activityType or "raid"] or addon.Store:GetGuild().needs.rules.raid
    local counts = self:GetRoleCounts(onlineOnly)
    local deficits = {}

    for key, target in pairs(rules) do
        deficits[key] = math.max(target - (counts[key] or 0), 0)
    end

    return {
        activityType = activityType or "raid",
        onlineOnly = onlineOnly and true or false,
        counts = counts,
        deficits = deficits,
        updatedAt = time(),
    }
end

function addon.NeedsService:GetSummaryText(activityType)
    local snapshot = self:GetNeedsSnapshot(activityType, true)
    return "Needs: " .. buildDeficitText(snapshot.deficits, ORDERED_NEED_KEYS, "No immediate shortages detected.")
end

function addon.NeedsService:FormatDeficitText(deficits, orderedKeys, emptyText)
    return buildDeficitText(deficits, orderedKeys, emptyText)
end

function addon.NeedsService:GetActivityNeedsSnapshot(activityType)
    local normalizedActivityType = activityType and string.lower(tostring(activityType)) or "all"
    local deficits = cloneDeficits()
    local activities = {}
    local groups = addon.GroupsService:ListGroups({
        activityType = normalizedActivityType == "all" and "all" or normalizedActivityType,
        sortBy = "start",
    })

    for _, group in ipairs(groups) do
        local activeOccurrenceStart = addon.GroupsService:GetResolvedOccurrenceStart(group)
        local planner = addon.GroupsService:GetPlannerData(group.id, activeOccurrenceStart)

        if planner then
            local plannerDeficits = cloneDeficits(planner.deficits)
            local openSlots = getDeficitTotal(plannerDeficits)

            if openSlots > 0 then
                deficits.tanks = deficits.tanks + plannerDeficits.tanks
                deficits.healers = deficits.healers + plannerDeficits.healers
                deficits.melee = deficits.melee + plannerDeficits.melee
                deficits.ranged = deficits.ranged + plannerDeficits.ranged
                deficits.dps = deficits.dps + plannerDeficits.dps

                activities[#activities + 1] = {
                    id = group.id,
                    eventName = planner.eventName or group.eventName or group.name or "Activity",
                    activityType = planner.activityType or group.activityType,
                    startAt = tonumber(planner.activeOccurrenceStart) or tonumber(group.nextStartAt) or tonumber(group.startAt) or 0,
                    deficits = plannerDeficits,
                    openSlots = openSlots,
                }
            end
        end
    end

    return {
        activityType = normalizedActivityType,
        deficits = deficits,
        activities = activities,
        openActivities = #activities,
        openSlots = getDeficitTotal(deficits),
        updatedAt = time(),
    }
end

function addon.NeedsService:GetActivitySummaryText(activityType)
    local snapshot = self:GetActivityNeedsSnapshot(activityType)

    if snapshot.openActivities <= 0 then
        return "No activity shortages tracked right now."
    end

    return string.format(
        "%d activities need %s",
        snapshot.openActivities,
        buildDeficitText(snapshot.deficits, { "tanks", "healers", "melee", "ranged" }, "roster coverage")
    )
end

function addon.NeedsService:GetCombinedNeedsSnapshot(activityType, onlineOnly)
    local rosterSnapshot = self:GetNeedsSnapshot(activityType, onlineOnly)
    local activitySnapshot = self:GetActivityNeedsSnapshot("all")
    local combinedDeficits = cloneDeficits(rosterSnapshot.deficits)

    combinedDeficits.tanks = combinedDeficits.tanks + activitySnapshot.deficits.tanks
    combinedDeficits.healers = combinedDeficits.healers + activitySnapshot.deficits.healers
    combinedDeficits.melee = combinedDeficits.melee + activitySnapshot.deficits.melee
    combinedDeficits.ranged = combinedDeficits.ranged + activitySnapshot.deficits.ranged
    combinedDeficits.dps = combinedDeficits.dps + activitySnapshot.deficits.dps

    return {
        activityType = activityType or "raid",
        onlineOnly = onlineOnly and true or false,
        roster = rosterSnapshot,
        planner = activitySnapshot,
        deficits = combinedDeficits,
        totalNeeds = getDeficitTotal(combinedDeficits),
        updatedAt = time(),
    }
end

function addon.NeedsService:GetCombinedSummaryText(activityType, onlineOnly)
    local snapshot = self:GetCombinedNeedsSnapshot(activityType, onlineOnly)
    local rosterText = buildDeficitText(snapshot.roster.deficits, { "tanks", "healers", "melee", "ranged" }, "covered")
    local plannerText = snapshot.planner.openActivities > 0 and buildDeficitText(snapshot.planner.deficits, { "tanks", "healers", "melee", "ranged" }, "covered") or "none"
    return string.format("Roster %s | Activities %s", rosterText, plannerText)
end
