-- ============================================================================
-- Vamoose's Companion - Pepe Perch
-- Decorative Pepe bird perched on the portrait frame (SVK-based rendering)
-- Uses PepeBuddy's proven technique: invisible anchor + SpellVisualKit overlay
-- ============================================================================

VC = VC or {}
VC.Pepe = {}

local ANCHOR_DISPLAY_ID = 93797  -- invisible humanoid anchor for SVK
local COSTUMES = {
    { id = 49669, name = "Original",     toyID = 122293, source = "Trans-Dimensional Bird Whistle toy. Earned from the achievement 'What A Strange, Interdimensional Trip It's Been' (complete WoD dungeons/raids with Pepe on your head)." },
    { id = 57227, name = "Pirate",       questID = 39268, source = "A Tiny Pirate Hat. Found in Spires of Arak near the Crow's Nest area in Draenor." },
    { id = 57228, name = "Knight",       questID = 39266, source = "A Tiny Plated Helm. Found in Talador near Vol'jin's Pride / Ft. Wrynn in Draenor." },
    { id = 57229, name = "Ninja",        questID = 39267, source = "A Tiny Ninja Shroud. Found in Gorgrond near Bastion Rise in Draenor." },
    { id = 57230, name = "Viking",       questID = 39265, source = "A Tiny Viking Helmet. Found in Nagrand near the Throne of the Elements in Draenor." },
    { id = 59131, name = "Scarecrow",    questID = 39865, source = "A Tiny Scarecrow Costume. Available during the Hallow's End seasonal event." },
    { id = 72523, name = "Traveler",     questID = 43695, source = "A Tiny Pair of Goggles. Found in Dalaran (Legion) -- Pepe spawns at random locations around the city." },
    { id = 82672, name = "Demon Hunter", toyID = 147537, source = "A Tiny Set of Warglaives. Purchased from Falara Nightsong in the Demon Hunter class hall (Fel Hammer). Toy item, account-wide." },
    { id = 100924, name = "Diver",       questID = 52277, source = "A Tiny Diving Helmet. Found in Boralus Harbor in Kul Tiras." },
    { id = 100671, name = "Pepe'jin",    questID = 52269, source = "A Tiny Voodoo Mask. Found in Dazar'alor in Zandalar." },
    { id = 115987, name = "Clockwork",   questID = 56911, source = "A Tiny Clockwork Key. Found in Mechagon." },
    { id = 122909, name = "Winter Veil", questID = 58901, source = "A Tiny Winter Hat. Available during the Feast of Winter Veil seasonal event." },
    { id = 148121, name = "Kyrian",      questID = 64136, source = "A Tiny Pair of Wings. Earned at Renown 56 with the Kyrian covenant in Bastion." },
    { id = 148122, name = "Necrolord",   questID = 64098, source = "A Tiny Vial of Slime. Earned at Renown 56 with the Necrolord covenant in Maldraxxus." },
    { id = 148123, name = "Night Fae",   questID = 64078, source = "A Tiny Winter Staff. Earned at Renown 56 with the Night Fae covenant in Ardenweald." },
    { id = 148125, name = "Venthyr",     questID = 64132, source = "A Tiny Sinstone. Earned at Renown 56 with the Venthyr covenant in Revendreth." },
    { id = 193447, name = "Tuskarr",     questID = 79551, source = "A Tiny Ear Warmer. Found near the Tuskarr in Iskaara, Dragon Isles." },
    { id = 193444, name = "Explorer",    questID = 79550, source = "A Tiny Explorer's Hat. Found at Dragonscale Basecamp, Dragon Isles." },
    { id = 193430, name = "Dragon",      questID = 79547, source = "A Tiny Dragon Goblet. Found in Valdrakken, Dragon Isles." },
}

local PERCH_SIZE = 60
local SVK_RETRY_DELAY = 0.2
local SVK_MAX_RETRIES = 3

-- ============================================================================
-- PUBLIC API
-- ============================================================================

function VC.Pepe:GetCostumes()
    return COSTUMES
end

function VC.Pepe:IsCostumeCollected(costume)
    if costume.toyID then
        return PlayerHasToy(costume.toyID)
    elseif costume.questID then
        return C_QuestLog.IsQuestFlaggedCompleted(costume.questID)
    end
    return false
end

function VC.Pepe:Initialize()
    if not VC.Portrait or not VC.Portrait.frame then return end

    self:CreatePerch(VC.Portrait.frame)
    self._retryToken = 0

    -- React to config changes
    VC.EventBus:Register("VC_STATE_CHANGED", function()
        self:UpdateVisibility()
    end)

    -- Re-apply after zone transitions, cutscenes, etc (SVK can get cleared)
    local eventFrame = CreateFrame("Frame")
    eventFrame:RegisterEvent("PLAYER_ENTERING_WORLD")
    eventFrame:SetScript("OnEvent", function()
        if self.frame and self.frame:IsShown() then
            C_Timer.After(0.5, function() self:ApplyCostume() end)
        end
    end)

    -- Self-heal when the perch is re-shown after UI was hidden (housing editor,
    -- cinematics, pet battles, etc all hide UIParent which clears SVK overlays).
    self.frame:HookScript("OnShow", function()
        C_Timer.After(0.2, function()
            if self.frame and self.frame:IsShown() then self:ApplyCostume() end
        end)
    end)

    -- Delay first application to avoid racing with portrait model load
    C_Timer.After(1.0, function()
        self:UpdateVisibility()
    end)
end

-- ============================================================================
-- PERCH FRAME
-- ============================================================================

function VC.Pepe:CreatePerch(portraitFrame)
    local f = CreateFrame("Frame", nil, portraitFrame)
    f:SetSize(PERCH_SIZE, PERCH_SIZE)
    f:SetPoint("CENTER", portraitFrame, "TOPLEFT", 25, 22)
    f:SetFrameLevel(portraitFrame:GetFrameLevel() + 5)
    f:EnableMouse(false)

    self.frame = f
    self.model = nil  -- created fresh each ApplyCostume (PepeBuddy pattern)
end

function VC.Pepe:UpdateVisibility()
    if not self.frame then return end
    local state = VC.Store:GetState()
    local frameStyle = state.config.portraitFrame or "atlas"
    local hideMinimal = state.config.pepeHideMinimal ~= false
    if state.config.showPepe and not (hideMinimal and frameStyle == "minimal") then
        self.frame:Show()
        local scale = state.config.pepeScale or 1.0
        self.frame:SetScale(scale)
        self.frame:ClearAllPoints()
        self.frame:SetPoint("CENTER", self.frame:GetParent(), "TOPLEFT", 25 / scale, 22)
        self:ApplyCostume()
    else
        self.frame:Hide()
    end
end

-- ============================================================================
-- SVK COSTUME APPLICATION
-- Follows PepeBuddy's EnsureModelReady pattern: destroy old model, create
-- fresh PlayerModel, set anchor, Undress, freeze animation, then apply SVK
-- ============================================================================

function VC.Pepe:ApplyCostume()
    if not self.frame then return end

    local state = VC.Store:GetState()
    local idx
    if state.config.pepeRandomCostume then
        idx = math.random(#COSTUMES)
    else
        idx = state.config.pepeCostume or 1
        if idx < 1 or idx > #COSTUMES then idx = 1 end
    end
    local costume = COSTUMES[idx]

    self._retryToken = (self._retryToken or 0) + 1
    local token = self._retryToken

    -- Destroy previous model and create fresh (PepeBuddy pattern — reuse is unreliable)
    if self.model then
        self.model:Hide()
    end

    local model = CreateFrame("PlayerModel", nil, self.frame)
    model:SetAllPoints()
    model:EnableMouse(false)
    self.model = model

    -- Load anchor model, undress, freeze, hide mesh (exact PepeBuddy EnsureModelReady)
    if model.ClearModel then pcall(model.ClearModel, model) end
    if model.SetDisplayInfo then pcall(model.SetDisplayInfo, model, ANCHOR_DISPLAY_ID) end
    if model.Undress then pcall(model.Undress, model) end
    if model.SetAlpha then model:SetAlpha(0) end
    if model.SetAnimation then pcall(model.SetAnimation, model, 0, 0) end
    if model.SetPaused then pcall(model.SetPaused, model, true) end

    -- Camera/position (PepeBuddy perch config)
    model:SetCamDistanceScale(0.70)
    model:SetPortraitZoom(0)
    model:SetPosition(0, -0.01, -1.00)
    model:SetFacing(0)

    -- Apply SVK immediately + retry (PepeBuddy pattern — no OnModelLoaded)
    self:TryApplySVK(costume.id, 0, token)
end

function VC.Pepe:TryApplySVK(svkID, attempt, token)
    if token ~= self._retryToken then return end
    if not self.model then return end

    local ok, result = pcall(self.model.ApplySpellVisualKit, self.model, svkID, false)
    if ok and result ~= false then return end

    if attempt < SVK_MAX_RETRIES then
        C_Timer.After(SVK_RETRY_DELAY, function()
            self:TryApplySVK(svkID, attempt + 1, token)
        end)
    end
end
