--[[ Achievement-like progress for named rares recorded by continent. ]]

local _, ns = ...

local RegionProgress = ns.NewModule("RegionProgress")
ns.Collection = ns.Collection or {}
ns.Collection.RegionProgress = RegionProgress

local regionByMap = {}

local function IsContinent(mapInfo)
    return Enum and Enum.UIMapType and mapInfo
        and mapInfo.mapType == Enum.UIMapType.Continent
end

local function ResolveRegion(mapID)
    if regionByMap[mapID] then
        return regionByMap[mapID]
    end
    local currentID, best = mapID, nil
    for _ = 1, 12 do
        local info = C_Map and C_Map.GetMapInfo and C_Map.GetMapInfo(currentID)
        if not info then break end
        best = { id = info.mapID or currentID, name = info.name or tostring(currentID) }
        if IsContinent(info) then break end
        if not info.parentMapID or info.parentMapID == 0 or info.parentMapID == currentID then
            break
        end
        currentID = info.parentMapID
    end
    regionByMap[mapID] = best or { id = mapID, name = tostring(mapID) }
    return regionByMap[mapID]
end

function RegionProgress:GetRegionForMap(mapID)
    return mapID and ResolveRegion(mapID) or nil
end

function RegionProgress:GetRegions()
    local indexed = {}
    for _, rare in ipairs(ns.Data.RareCatalog:GetAll()) do
        if rare.mapID then
            local region = ResolveRegion(rare.mapID)
            local record = indexed[region.id]
            if not record then
                record = { id = region.id, name = region.name, npcIDs = {} }
                indexed[region.id] = record
            end
            record.npcIDs[rare.npcID] = true
        end
    end

    local regions = {}
    for _, region in pairs(indexed) do
        region.collected, region.total = ns.Collection.RareState:GetProgress(region.npcIDs)
        region.complete = region.total > 0 and region.collected == region.total
        regions[#regions + 1] = region
    end
    table.sort(regions, function(a, b) return a.name < b.name end)
    return regions
end

function RegionProgress:CheckCompletions()
    local account = ns.Database:GetAccountData()
    if not account then return end
    account.namedRareRegionCompletions = account.namedRareRegionCompletions or {}
    for _, region in ipairs(self:GetRegions()) do
        if region.complete and not account.namedRareRegionCompletions[region.id] then
            account.namedRareRegionCompletions[region.id] = time()
            ns.Events:Send("REGION_COMPLETED", region)
        end
    end
end

function RegionProgress:OnEnable()
    ns.Events:Subscribe("COLLECTION_CHANGED", self, function()
        self:CheckCompletions()
    end)
    ns.Events:Subscribe("RARE_COLLECTION_CHANGED", self, function()
        self:CheckCompletions()
    end)

    -- Existing collections also deserve their seal after upgrading to the
    -- regional system.  Delay until the player and saved character are ready.
    C_Timer.After(1, function() self:CheckCompletions() end)
end
