--[[
============================================================================
Enhanced Pet Tracker  -  Core/PetAPI.lua
============================================================================
Collection state for battle pets, via C_PetJournal (the Pet Journal API,
present since MoP 5.0 — so available in 5.4.8).

Battle pets are keyed by speciesID. Unlike mounts you can own several of the
same species, so "collected" means GetNumCollectedInfo(speciesID) > 0.

  C_PetJournal.GetNumCollectedInfo(speciesID)   -> numCollected, limit
  C_PetJournal.GetPetInfoBySpeciesID(speciesID) -> name, icon, petType,
        companionID, sourceText, description, isWild, canBattle, ...

We query per-species straight from our PetData set rather than walking the
whole journal, so the addon never fights the journal's active filters.
============================================================================
]]--

local ADDON_NAME, NS = ...
local EPT = NS.EPT
if not EPT then return end

EPT.PetAPI = EPT.PetAPI or {}
local API = EPT.PetAPI

-- speciesID -> { collected, name, icon }
API._cache          = {}
API._scanned        = false
API._collectedCount = 0

local function hasJournal()
    return C_PetJournal and C_PetJournal.GetNumCollectedInfo
end

function API:Refresh()
    wipe(self._cache)
    self._collectedCount = 0
    local data = EPT.PetData
    if not data or not hasJournal() then
        self._scanned = true
        return
    end

    for speciesID in pairs(data) do
        local numCollected = C_PetJournal.GetNumCollectedInfo(speciesID)
        local collected = (numCollected or 0) > 0
        local name, icon
        if C_PetJournal.GetPetInfoBySpeciesID then
            name, icon = C_PetJournal.GetPetInfoBySpeciesID(speciesID)
        end
        self._cache[speciesID] = {
            collected = collected, name = name, icon = icon,
        }
        if collected then self._collectedCount = self._collectedCount + 1 end
    end

    self._scanned = true
    EPT:Debug("PetAPI", "scanned: " .. self._collectedCount
        .. " of our pets collected")
    EPT:Emit("EPT_COLLECTION_CHANGED")
end

local function ensure()
    if not API._scanned then API:Refresh() end
end

function API:IsCollected(speciesID)
    ensure()
    local c = self._cache[speciesID]
    return c ~= nil and c.collected == true
end

function API:GetProgress()
    ensure()
    local data = EPT.PetData
    if not data then return 0, 0 end
    local owned, total = 0, 0
    for speciesID in pairs(data) do
        total = total + 1
        if self:IsCollected(speciesID) then owned = owned + 1 end
    end
    return owned, total
end

function API:GetOwnedCount()
    ensure()
    return self._collectedCount
end

-- Names / icons: journal first, then GetItemInfo on the teaching item.
function API:GetName(speciesID, itemID)
    local c = self._cache[speciesID]
    if c and type(c.name) == "string" and c.name ~= "" then return c.name end
    if C_PetJournal and C_PetJournal.GetPetInfoBySpeciesID then
        local n = C_PetJournal.GetPetInfoBySpeciesID(speciesID)
        if type(n) == "string" and n ~= "" then return n end
    end
    if itemID then
        local iname = GetItemInfo(itemID)
        if type(iname) == "string" and iname ~= "" then return iname end
    end
    return "Pet #" .. tostring(speciesID)
end

function API:GetIcon(speciesID, itemID)
    local c = self._cache[speciesID]
    if c and c.icon then return c.icon end
    if C_PetJournal and C_PetJournal.GetPetInfoBySpeciesID then
        local _, icon = C_PetJournal.GetPetInfoBySpeciesID(speciesID)
        if icon then return icon end
    end
    if itemID then
        local tex = select(10, GetItemInfo(itemID))
        if tex then return tex end
    end
    return "Interface\\Icons\\INV_Box_PetCarrier_01"
end

local QUALITY_HEX = {
    [1] = "ffffffff", [2] = "ff1eff00", [3] = "ff0070dd",
    [4] = "ffa335ee", [5] = "ffff8000",
}
function API:QualityColor(q)
    return "|c" .. (QUALITY_HEX[q or 1] or QUALITY_HEX[1])
end

-- Best-effort summon: find a petID for this species in the journal, then
-- summon it. Pet summon needs a per-pet GUID, so this scans the journal.
function API:Summon(speciesID)
    if not (C_PetJournal and C_PetJournal.GetNumPets) then return false end
    local num = C_PetJournal.GetNumPets() or 0
    for i = 1, num do
        local petID, sID, owned = C_PetJournal.GetPetInfoByIndex(i)
        if sID == speciesID and owned and petID then
            if C_PetJournal.SummonPetByGUID then
                C_PetJournal.SummonPetByGUID(petID)
                return true
            end
        end
    end
    return false
end

function API:IsObtainable(rec)
    return rec and rec.u == nil
end

EPT:RegisterInit(function()
    API:Refresh()
    local f = CreateFrame("Frame")
    pcall(f.RegisterEvent, f, "PET_JOURNAL_LIST_UPDATE")
    pcall(f.RegisterEvent, f, "COMPANION_LEARNED")
    pcall(f.RegisterEvent, f, "COMPANION_UPDATE")
    local pending = false
    f:SetScript("OnEvent", function()
        if pending then return end
        pending = true
        C_Timer.After(0.3, function()
            pending = false
            API:Refresh()
        end)
    end)
    API._eventFrame = f
end)
