local _, ns = ...

------------------------------------------------------------
-- PI candidate ranking.
--
-- Public API:
--   ns.PI:BuildCandidateList(roster, mode) -> sorted list
--   ns.PI:RankTargets(mode)                -> sorted list from current raid
--
-- The manual picker uses these to annotate DPS rows with bloodmallet
-- scores + a "(best)" tag. When inspect data hasn't been collected
-- yet (ns.RaidInspectData empty) the list is empty and the picker
-- falls back to name-sort.
--
-- The previous auto-assign flow (EnsureScan / IsDataReady /
-- AutoAssign / Recommend) was removed: WoW's serial inspect API made
-- it unreliable in large raids. Assignments are now done through the
-- manual picker only.
------------------------------------------------------------

ns.PI = ns.PI or {}
local PI = ns.PI

------------------------------------------------------------
-- Candidate list
------------------------------------------------------------
-- Given a `roster` (list from RaidUI.GetRaidRoster) filter down to
-- DPS that have bloodmallet coverage, merge with per-guid inspect
-- data, and rank by the requested mode.
function PI:BuildCandidateList(roster, mode)
    mode = (mode or "st"):lower()

    local byName = {}
    for _, p in ipairs(roster or {}) do
        byName[p.name] = p
    end

    local scored = {}
    for _, data in pairs(ns.RaidInspectData or {}) do
        local rosterEntry = data.name and byName[data.name]
        if rosterEntry
           and (rosterEntry.role == "DAMAGER")   -- PI goes to DPS only; tanks opt in manually
           and data.specID and data.specID ~= 0
           and self:IsSpecScored(data.specID) then
            table.insert(scored, {
                name              = data.name,
                guid              = data.guid,
                specID            = data.specID,
                ilvl              = data.ilvl or 0,
                class             = data.class,
                group             = rosterEntry.group,
                qualityMultiplier = data.qualityMultiplier or 1,
                totalPenalty      = data.totalPenalty or 0,
            })
        end
    end

    return self.Scoring:RankByMode(scored, mode:upper())
end

function PI:RankTargets(mode)
    -- Pull the roster via the same helper RaidUI uses. We inline it
    -- loosely here to avoid coupling: the roster is only name + role +
    -- group, which is cheap to rebuild from GetRaidRosterInfo.
    local roster = {}
    local n = GetNumGroupMembers()
    if n == 0 then return {} end

    if IsInRaid() then
        for i = 1, n do
            local name, _, subgroup = GetRaidRosterInfo(i)
            if name then
                local shortName = name:match("^([^%-]+)") or name
                table.insert(roster, {
                    name  = shortName,
                    role  = UnitGroupRolesAssigned("raid" .. i) or "NONE",
                    group = subgroup or 1,
                })
            end
        end
    else
        local units = { "player" }
        for i = 1, n - 1 do table.insert(units, "party" .. i) end
        for _, u in ipairs(units) do
            if UnitExists(u) then
                table.insert(roster, {
                    name  = UnitName(u),
                    role  = UnitGroupRolesAssigned(u) or "NONE",
                    group = 1,
                })
            end
        end
    end

    return self:BuildCandidateList(roster, mode)
end
