--[[
    Independent named-rare index. Unlike an appearance, a rare record means
    one exact NPC identity. This keeps zone hunts complete without pretending
    that two named creatures sharing one skin are the same capture.
]]

local _, ns = ...

local RareCatalog = ns.NewModule("RareCatalog")
ns.Data = ns.Data or {}
ns.Data.RareCatalog = RareCatalog

local byNPC = {}
local byName = {}
local byMap = {}
local byDisplay = {}
local all = {}
local EMPTY = {}

function RareCatalog:Register(record)
    if type(record) ~= "table" or type(record.npcID) ~= "number"
        or type(record.name) ~= "string" or byNPC[record.npcID] then
        ns.Debug:Warn("RARE_DATA", "rejected rare record %s", tostring(record and record.npcID))
        return false
    end

    byNPC[record.npcID] = record
    all[#all + 1] = record

    local existingName = byName[record.name]
    if existingName == nil then
        byName[record.name] = record
    elseif existingName ~= record then
        -- false means the name is shared and is not sufficient evidence for
        -- identifying an active pet after Retail changes its creature id.
        byName[record.name] = false
    end

    for _, displayID in ipairs(record.displayIDs or EMPTY) do
        local existing = byDisplay[displayID]
        if existing == nil then
            byDisplay[displayID] = record
        elseif existing ~= record then
            -- false means the skin is shared and therefore cannot prove which
            -- named rare is present in a stable snapshot.
            byDisplay[displayID] = false
        end
    end

    local maps = {}
    if record.mapID then maps[record.mapID] = true end
    for _, location in ipairs(record.locations or EMPTY) do
        if location.mapID then maps[location.mapID] = true end
    end
    for mapID in pairs(maps) do
        byMap[mapID] = byMap[mapID] or {}
        byMap[mapID][#byMap[mapID] + 1] = record
    end
    return true
end

function RareCatalog:GetUniqueByDisplayID(displayID)
    return byDisplay[displayID] or nil
end

function RareCatalog:Get(npcID)
    return byNPC[npcID]
end

function RareCatalog:GetUniqueByName(name)
    return name and byName[name] or nil
end

function RareCatalog:GetByMap(mapID)
    return byMap[mapID] or EMPTY
end

function RareCatalog:GetAll()
    return all
end

function RareCatalog:GetLocations(npcID, mapID)
    local record = byNPC[npcID]
    if not record then return EMPTY end
    if not mapID then return record.locations or EMPTY end
    local result = {}
    for _, location in ipairs(record.locations or EMPTY) do
        if location.mapID == mapID then result[#result + 1] = location end
    end
    return result
end
