-- Transmoggin - Copyright (c) 2026 Rooster_Roost. All Rights Reserved.
-- Alpha 36: exact quest reward intelligence.
local T=Transmoggin

local function ensureDB()
    T.db=T.db or TransmogginDB or {}
    TransmogginDB=T.db
    T.db.questIntel=T.db.questIntel or {version=1,byQuest={},byItem={}}
    T.db.questIntel.byQuest=T.db.questIntel.byQuest or {}
    T.db.questIntel.byItem=T.db.questIntel.byItem or {}
    return T.db.questIntel
end

local function questTitle(questID)
    local title
    if C_QuestLog and C_QuestLog.GetTitleForQuestID then
        local ok,v=pcall(C_QuestLog.GetTitleForQuestID,questID); if ok then title=v end
    elseif C_QuestLog and C_QuestLog.GetQuestInfo then
        local ok,v=pcall(C_QuestLog.GetQuestInfo,questID); if ok then title=v end
    end
    return (type(title)=="string" and title~="") and title or nil
end

local function addItemLink(db,questID,itemID,row)
    if not itemID or itemID==0 then return end
    local list=db.byItem[itemID]; if not list then list={}; db.byItem[itemID]=list end
    for i=1,#list do if list[i].questID==questID and list[i].rewardType==row.rewardType then
        for k,v in pairs(row) do list[i][k]=v end; return
    end end
    list[#list+1]=row
end

function T:CaptureQuestRewards(questID,context)
    questID=tonumber(questID); if not questID or questID<=0 then return false end
    local db=ensureDB()
    local title=questTitle(questID)
    local q=db.byQuest[questID] or {questID=questID,rewards={}}
    q.title=title or q.title
    q.provider="Blizzard Quest API"
    q.verified=true
    q.updated=time and time() or 0
    if context then
        q.zone=context.zone or q.zone
        q.giver=context.giver or q.giver
    end
    q.rewards={}

    local function capture(kind,countFn,infoFn)
        if not countFn or not infoFn then return end
        local okCount,count=pcall(countFn,questID); if not okCount then return end
        count=tonumber(count) or 0
        for i=1,count do
            local ok,name,texture,qty,quality,isUsable,itemID=pcall(infoFn,i,questID)
            if ok and itemID and itemID>0 then
                local row={questID=questID,quest=q.title,rewardType=kind,quantity=qty or 1,itemID=itemID,zone=q.zone,giver=q.giver,confidence="VERIFIED",provider="Blizzard Quest API"}
                q.rewards[#q.rewards+1]=row
                addItemLink(db,questID,itemID,row)
            end
        end
    end

    capture("Guaranteed",GetNumQuestLogRewards,GetQuestLogRewardInfo)
    capture("Choice",GetNumQuestLogChoices,GetQuestLogChoiceInfo)
    db.byQuest[questID]=q
    return #q.rewards>0
end

function T:GetQuestIntelForItem(itemID)
    local db=ensureDB(); return db.byItem[tonumber(itemID)]
end

function T:RefreshVisibleQuestIntel()
    -- Current quest log: bounded and safe; no global quest-ID brute force.
    if C_QuestLog and C_QuestLog.GetNumQuestLogEntries and C_QuestLog.GetInfo then
        local ok,n=pcall(C_QuestLog.GetNumQuestLogEntries)
        n=ok and tonumber(n) or 0
        for i=1,n do
            local okInfo,info=pcall(C_QuestLog.GetInfo,i)
            if okInfo and info and info.questID and info.questID>0 and not info.isHeader then
                self:CaptureQuestRewards(info.questID)
            end
        end
    end
    -- Retail exposes completed quest IDs. Harvest exact rewards for quests the
    -- account has actually completed, again without scanning arbitrary IDs.
    if C_QuestLog and C_QuestLog.GetAllCompletedQuestIDs then
        local ok,ids=pcall(C_QuestLog.GetAllCompletedQuestIDs)
        if ok and type(ids)=="table" then
            for i=1,#ids do self:CaptureQuestRewards(ids[i]) end
        end
    end
end

local f=CreateFrame("Frame")
f:RegisterEvent("PLAYER_LOGIN")
f:RegisterEvent("QUEST_ACCEPTED")
f:RegisterEvent("QUEST_DETAIL")
f:RegisterEvent("QUEST_COMPLETE")
f:RegisterEvent("QUEST_TURNED_IN")
f:RegisterEvent("QUEST_LOG_UPDATE")
f:SetScript("OnEvent",function(_,event,...)
    if event=="PLAYER_LOGIN" then
        if C_Timer and C_Timer.After then C_Timer.After(2,function() T:RefreshVisibleQuestIntel() end) else T:RefreshVisibleQuestIntel() end
        return
    end
    local questID
    if event=="QUEST_ACCEPTED" then
        local a,b=...; questID=tonumber(b) or tonumber(a)
    elseif event=="QUEST_TURNED_IN" then questID=tonumber((...))
    end
    if questID then T:CaptureQuestRewards(questID) end
    if event=="QUEST_DETAIL" or event=="QUEST_COMPLETE" then
        local qid=GetQuestID and GetQuestID() or nil
        if qid and qid>0 then
            local giver=UnitName and UnitName("questnpc") or nil
            local zone=GetRealZoneText and GetRealZoneText() or nil
            T:CaptureQuestRewards(qid,{giver=giver,zone=zone})
        end
    elseif event=="QUEST_LOG_UPDATE" then
        -- Debounce noisy updates.
        if not T._questIntelPending and C_Timer and C_Timer.After then
            T._questIntelPending=true
            C_Timer.After(1,function() T._questIntelPending=nil; T:RefreshVisibleQuestIntel() end)
        end
    end
end)
