local T=Transmoggin
local C=T.COLORS

T.PHOTO_BACKGROUNDS={
    {key="woodland", name="Woodland Ruins"},
    {key="fantasy", name="Fantasy"},
    {key="horde", name="Horde Cathedral"},
    {key="mountains", name="Mountains"},
    {key="mystical", name="Mystical"},
    {key="neonverse", name="Neonverse"},
    {key="alliance", name="Alliance Castle"},
    {key="caves", name="Caves"},
    {key="elvish", name="Elvish"},
}


local function rgba(t) return t[1],t[2],t[3],t[4] end
local function frame(tp,name,parent,template)
    if BackdropTemplateMixin and not template and tp~="DressUpModel" then template="BackdropTemplate" end
    return CreateFrame(tp,name,parent,template)
end
local function skin(f,bg,border,edge)
    if not f.SetBackdrop then return end
    f:SetBackdrop({bgFile="Interface\\Buttons\\WHITE8X8",edgeFile="Interface\\Buttons\\WHITE8X8",edgeSize=edge or 1})
    f:SetBackdropColor(rgba(bg)); f:SetBackdropBorderColor(rgba(border))
end
local function fs(p,s,c,font)
    local x=p:CreateFontString(nil,"OVERLAY",font or "GameFontNormal")
    x:SetFont(STANDARD_TEXT_FONT,s,""); x:SetTextColor(rgba(c)); return x
end
local function button(p,label,w,h)
    local b=frame("Button",nil,p); b:SetSize(w,h); skin(b,{0.035,0.028,0.022,.94},C.gold2)
    b.txt=fs(b,11,C.gold); b.txt:SetPoint("CENTER"); b.txt:SetText(label)
    b:SetScript("OnEnter",function(self) if self.SetBackdropBorderColor then self:SetBackdropBorderColor(rgba(C.gold)) end end)
    b:SetScript("OnLeave",function(self) if self.SetBackdropBorderColor then self:SetBackdropBorderColor(rgba(C.gold2)) end end)
    return b
end

T.PHOTO_ANIMATIONS={
    {name="Idle",id=0,group="POSE"},
    {name="Ready",id=25,group="POSE"},
    {name="Kneel",id=75,group="POSE"},
    {name="Sit",id=97,group="POSE"},
    {name="Crouch",id=120,group="POSE"},
    {name="Salute",id=113,group="EMOTE"},
    {name="Wave",id=67,group="EMOTE"},
    {name="Cheer",id=68,group="EMOTE"},
    {name="Dance",id=69,group="EMOTE"},
    {name="Laugh",id=70,group="EMOTE"},
    {name="Roar",id=74,group="EMOTE"},
    {name="Flex",id=82,group="EMOTE"},
    {name="Point",id=84,group="EMOTE"},
    {name="Bow",id=66,group="EMOTE"},
    {name="Shrug",id=65,group="EMOTE"},
    {name="Applaud",id=80,group="EMOTE"},
    {name="Spin",id=126,group="ACTION"},
    {name="Run",id=5,group="ACTION"},
}

local function tryOnPiece(model,piece)
    if not model or not piece or not model.TryOn then return end
    local sourceID=piece.previewSourceID or piece.sourceID or piece.itemModID
    if sourceID and sourceID~=0 and pcall(model.TryOn,model,sourceID) then return end
    if piece.itemLink and pcall(model.TryOn,model,piece.itemLink) then return end
    if piece.itemID and piece.itemID~=0 then pcall(model.TryOn,model,piece.itemID) end
end

function T:RefreshPhotoModel()
    local m=self.photoModel; if not m then return end

    -- Photo Mode starts from the player's REAL equipped appearance. Do not Undress()
    -- here: doing so removed equipped weapons/armor and could leave temporary ghost
    -- silhouettes while source models were streaming in on first open.
    self.state.photoRefreshToken=(self.state.photoRefreshToken or 0)+1
    local token=self.state.photoRefreshToken
    if m.ClearModel then pcall(m.ClearModel,m) end
    pcall(m.SetUnit,m,"player")

    local function finishDress()
        if token~=T.state.photoRefreshToken or not T.photoModel or m~=T.photoModel then return end

        -- A Transmoggin working look acts as overrides on top of equipped gear.
        -- Empty/unselected slots therefore keep exactly what the character is wearing.
        for _,slot in ipairs(T.SLOTS or {}) do
            local piece=T.state.working and T.state.working.pieces and T.state.working.pieces[slot.key]
            if piece then tryOnPiece(m,piece) end
        end

        if m.SetSheathed then pcall(m.SetSheathed,m,T.state.photoSheathed~=false,false) end
        local anim=T.state.photoAnimation or 0
        if m.SetAnimation then pcall(m.SetAnimation,m,anim) end
    end

    -- Give DressUpModel one frame to finish SetUnit before applying transmog source
    -- overrides. This prevents the one-time floating/silhouette gear artifacts.
    if C_Timer and C_Timer.After then C_Timer.After(0.06,finishDress) else finishDress() end
end

function T:SetPhotoAnimation(animID,name)
    local m=self.photoModel; if not m then return end
    if m.HasAnimation then
        local ok,has=pcall(m.HasAnimation,m,animID)
        if ok and not has then self:Print((name or "That pose").." is not supported by this character model."); return end
    end
    self.state.photoAnimation=animID
    if m.SetAnimation then pcall(m.SetAnimation,m,animID) end
    if self.photoPoseName then self.photoPoseName:SetText(name or ("Animation "..tostring(animID))) end
end

function T:SetPhotoControlsVisible(show)
    if not self.photoMode then return end
    self.state.photoControlsVisible=show and true or false
    if self.photoMode.controls then self.photoMode.controls:SetShown(show) end
    if self.photoMode.topBar then self.photoMode.topBar:SetShown(show) end
    if not show and self.photoMode.backgroundPanel then self.photoMode.backgroundPanel:Hide() end
    -- The camera toggle remains visible so Photo Mode can always be exited.
    if self.photoMode.toggle then self.photoMode.toggle:Show() end
end

function T:CapturePhoto()
    if not self.photoMode then return end
    local was=self.state.photoControlsVisible~=false
    self:SetPhotoControlsVisible(false)
    if self.photoMode.toggle then self.photoMode.toggle:Hide() end
    local function snap()
        if Screenshot then pcall(Screenshot) end
        local function restore()
            if T.photoMode and T.photoMode:IsShown() then
                T:SetPhotoControlsVisible(was)
                if T.photoMode.toggle then T.photoMode.toggle:Show() end
            end
        end
        if C_Timer and C_Timer.After then C_Timer.After(.45,restore) else restore() end
    end
    if C_Timer and C_Timer.After then C_Timer.After(.08,snap) else snap() end
end

function T:GetPhotoBackgroundDef(key)
    for _,bg in ipairs(self.PHOTO_BACKGROUNDS or {}) do
        if bg.key==key then return bg end
    end
    return (self.PHOTO_BACKGROUNDS or {})[1]
end

function T:SetPhotoBackground(key,save)
    local p=self.photoMode
    local def=self:GetPhotoBackgroundDef(key)
    if not def then return end
    self.state.photoBackground=def.key
    if save and self.db and self.db.profile then
        self.db.profile.photo=self.db.profile.photo or {}
        self.db.profile.photo.background=def.key
    end
    if p and p.bgL and p.bgR then
        p.bgL:SetTexture(self.MEDIA.."photo_bg_"..def.key.."_left.tga")
        p.bgR:SetTexture(self.MEDIA.."photo_bg_"..def.key.."_right.tga")
    end
    if p and p.backgroundName then p.backgroundName:SetText(def.name) end
    if p and p.backgroundRows then
        for _,row in ipairs(p.backgroundRows) do
            if row.SetBackdropBorderColor then
                if row.bgKey==def.key then row:SetBackdropBorderColor(rgba(C.gold)) else row:SetBackdropBorderColor(rgba(C.gold2)) end
            end
        end
    end
end

function T:TogglePhotoBackgroundSelector()
    if not self.photoMode or not self.photoMode.backgroundPanel then return end
    local panel=self.photoMode.backgroundPanel
    panel:SetShown(not panel:IsShown())
end

function T:CreatePhotoMode()
    if self.photoMode then return end
    local p=frame("Frame","TransmogginPhotoMode",UIParent); self.photoMode=p
    p:SetAllPoints(UIParent); p:SetFrameStrata("FULLSCREEN_DIALOG"); p:SetFrameLevel(500); p:EnableMouse(true); p:Hide()

    -- Photo backgrounds are authored at 1580x880 and split into two WoW-safe
    -- 1024x1024 tiles. Only the currently selected pair is loaded by the scene.
    local bgL=p:CreateTexture(nil,"BACKGROUND")
    bgL:SetPoint("TOPLEFT"); bgL:SetPoint("BOTTOMLEFT"); bgL:SetWidth(UIParent:GetWidth()/2); bgL:SetTexCoord(0,790/1024,0,880/1024)
    local bgR=p:CreateTexture(nil,"BACKGROUND")
    bgR:SetPoint("TOPRIGHT"); bgR:SetPoint("BOTTOMRIGHT"); bgR:SetWidth(UIParent:GetWidth()/2); bgR:SetTexCoord(0,790/1024,0,880/1024)
    p.bgL,p.bgR=bgL,bgR
    p:SetScript("OnSizeChanged",function(self,w) if self.bgL then self.bgL:SetWidth(w/2); self.bgR:SetWidth(w/2) end end)

    local vignette=p:CreateTexture(nil,"BORDER"); vignette:SetAllPoints(); vignette:SetTexture("Interface\\Buttons\\WHITE8X8"); vignette:SetVertexColor(0,0,0,.12)

    local model=CreateFrame("DressUpModel",nil,p); self.photoModel=model
    -- Compose the character slightly left of center and lower in the scene so
    -- the feet land closer to the foreground medallion and the background's
    -- focal architecture remains visible. Percent-based horizontal anchors
    -- keep the composition consistent across supported resolutions.
    model:SetPoint("TOPLEFT",UIParent,"TOPLEFT",UIParent:GetWidth()*.14,-80)
    model:SetPoint("BOTTOMRIGHT",UIParent,"BOTTOMRIGHT",-UIParent:GetWidth()*.22,-20)
    model:SetUnit("player"); model:EnableMouse(true); model:EnableMouseWheel(true)
    if model.SetCamDistanceScale then pcall(model.SetCamDistanceScale,model,.78) end
    model:SetScript("OnMouseDown",function(m,btn) if btn=="LeftButton" then m.__drag=true; m.__x=GetCursorPosition() end end)
    model:SetScript("OnMouseUp",function(m) m.__drag=false end)
    model:SetScript("OnUpdate",function(m) if m.__drag and m.SetFacing then local x=GetCursorPosition(); local dx=(x-(m.__x or x))/180; m.__x=x; m:SetFacing((m:GetFacing() or 0)+dx) end end)
    model:SetScript("OnMouseWheel",function(m,d)
        if not m.SetCamDistanceScale then return end
        T.state.photoZoom=math.max(.45,math.min(2.20,(T.state.photoZoom or .78)-(d*.08)))
        pcall(m.SetCamDistanceScale,m,T.state.photoZoom)
    end)

    local top=frame("Frame",nil,p); p.topBar=top; top:SetPoint("TOP",0,-16); top:SetSize(420,62); skin(top,{0.02,0.016,0.013,.90},{0.45,0.24,0.06,1},2)
    local logo=top:CreateTexture(nil,"ARTWORK"); logo:SetTexture(self.ROOSTER); logo:SetSize(50,50); logo:SetPoint("LEFT",12,0)
    local ttl=fs(top,24,C.gold); ttl:SetPoint("LEFT",logo,"RIGHT",10,7); ttl:SetText("PHOTO MODE")
    self.photoPoseName=fs(top,10,C.muted); self.photoPoseName:SetPoint("LEFT",logo,"RIGHT",10,-15); self.photoPoseName:SetText("Idle")

    local toggle=frame("Button",nil,p); p.toggle=toggle; toggle:SetSize(62,62); toggle:SetPoint("TOPLEFT",18,-18); skin(toggle,{0.04,0.025,0.018,.96},C.gold,2)
    toggle.icon=toggle:CreateTexture(nil,"ARTWORK"); toggle.icon:SetPoint("TOPLEFT",3,-3); toggle.icon:SetPoint("BOTTOMRIGHT",-3,3); toggle.icon:SetTexture(self.MEDIA.."photo.tga"); toggle.icon:SetTexCoord(0,1,0,1)
    toggle:SetScript("OnClick",function() T:TogglePhotoMode() end)
    toggle:SetScript("OnEnter",function(self) if T.ShowHelpTooltip then T:ShowHelpTooltip(self,"Exit Photo Mode","Return to the full Transmoggin salon.","ANCHOR_RIGHT") end end)
    toggle:SetScript("OnLeave",function() if GameTooltip then GameTooltip:Hide() end end)

    local c=frame("Frame",nil,p); p.controls=c; c:SetPoint("RIGHT",-24,0); c:SetSize(270,600); skin(c,{0.025,0.020,0.016,.91},{0.42,0.22,0.06,1},2)
    local ct=fs(c,18,C.gold); ct:SetPoint("TOPLEFT",16,-15); ct:SetText("POSE STUDIO")
    local hint=fs(c,10,C.muted); hint:SetPoint("TOPLEFT",16,-42); hint:SetPoint("RIGHT",-16,0); hint:SetJustifyH("LEFT"); hint:SetText("Choose a pose or emote. Drag the character to rotate. Mouse wheel zooms.")

    local bgButton=button(c,"BACKGROUND",98,24); bgButton:SetPoint("TOPRIGHT",-15,-14)
    bgButton:SetScript("OnClick",function() T:TogglePhotoBackgroundSelector() end)
    bgButton:SetScript("OnEnter",function(self) if T.ShowHelpTooltip then T:ShowHelpTooltip(self,"Photo Backgrounds","Choose the scene behind your character. Your choice is remembered.","ANCHOR_LEFT") end end)
    bgButton:SetScript("OnLeave",function() if GameTooltip then GameTooltip:Hide() end end)

    local bgPanel=frame("Frame",nil,p); p.backgroundPanel=bgPanel
    bgPanel:SetSize(430,300); bgPanel:SetPoint("RIGHT",c,"LEFT",-12,20); skin(bgPanel,{0.018,0.015,0.013,.96},{0.45,0.24,0.06,1},2); bgPanel:Hide()
    local bgt=fs(bgPanel,18,C.gold); bgt:SetPoint("TOPLEFT",14,-13); bgt:SetText("PHOTO BACKGROUNDS")
    local current=fs(bgPanel,10,C.muted); p.backgroundName=current; current:SetPoint("TOPLEFT",14,-34); current:SetText("")
    local close=button(bgPanel,"X",26,24); close:SetPoint("TOPRIGHT",-8,-8); close:SetScript("OnClick",function() bgPanel:Hide() end)
    p.backgroundRows={}
    for i,bg in ipairs(self.PHOTO_BACKGROUNDS or {}) do
        local col=(i-1)%3; local row=math.floor((i-1)/3)
        local b=frame("Button",nil,bgPanel); b:SetSize(126,72); b:SetPoint("TOPLEFT",14+col*136,-50-row*80); skin(b,{0.028,0.022,0.018,.96},C.gold2,1); b.bgKey=bg.key
        local tex=b:CreateTexture(nil,"ARTWORK"); tex:SetPoint("TOPLEFT",3,-3); tex:SetPoint("BOTTOMRIGHT",-3,18); tex:SetTexture(T.MEDIA.."photo_bg_"..bg.key.."_thumb.tga"); tex:SetTexCoord(0,1,56/256,200/256)
        local label=fs(b,9,C.text); label:SetPoint("BOTTOMLEFT",4,4); label:SetPoint("BOTTOMRIGHT",-4,4); label:SetJustifyH("CENTER"); label:SetText(bg.name)
        b:SetScript("OnClick",function() T:SetPhotoBackground(bg.key,true); bgPanel:Hide() end)
        b:SetScript("OnEnter",function(self) if self.SetBackdropBorderColor then self:SetBackdropBorderColor(rgba(C.gold)) end end)
        b:SetScript("OnLeave",function(self) if self.SetBackdropBorderColor then if T.state.photoBackground==self.bgKey then self:SetBackdropBorderColor(rgba(C.gold)) else self:SetBackdropBorderColor(rgba(C.gold2)) end end end)
        table.insert(p.backgroundRows,b)
    end

    local y=-82
    for i,a in ipairs(self.PHOTO_ANIMATIONS) do
        local b=button(c,a.name,112,27)
        local col=(i-1)%2; local row=math.floor((i-1)/2)
        b:SetPoint("TOPLEFT",15+col*122,-82-row*33)
        b:SetScript("OnClick",function() T:SetPhotoAnimation(a.id,a.name) end)
    end

    local toolsY=-395
    local sheathe=button(c,"SHEATHE",112,28); sheathe:SetPoint("TOPLEFT",15,toolsY); sheathe:SetScript("OnClick",function() T.state.photoSheathed=true; T:RefreshPhotoModel() end)
    local draw=button(c,"DRAW WEAPONS",112,28); draw:SetPoint("LEFT",sheathe,"RIGHT",10,0); draw:SetScript("OnClick",function() T.state.photoSheathed=false; T:RefreshPhotoModel() end)
    local zIn=button(c,"ZOOM +",112,28); zIn:SetPoint("TOPLEFT",15,toolsY-38); zIn:SetScript("OnClick",function() T.state.photoZoom=math.max(.45,(T.state.photoZoom or .78)-.10); if T.photoModel.SetCamDistanceScale then pcall(T.photoModel.SetCamDistanceScale,T.photoModel,T.state.photoZoom) end end)
    local zOut=button(c,"ZOOM -",112,28); zOut:SetPoint("LEFT",zIn,"RIGHT",10,0); zOut:SetScript("OnClick",function() T.state.photoZoom=math.min(2.20,(T.state.photoZoom or .78)+.10); if T.photoModel.SetCamDistanceScale then pcall(T.photoModel.SetCamDistanceScale,T.photoModel,T.state.photoZoom) end end)
    local reset=button(c,"RESET VIEW",234,28); reset:SetPoint("TOPLEFT",15,toolsY-76); reset:SetScript("OnClick",function() T.state.photoZoom=.78; if T.photoModel.SetCamDistanceScale then pcall(T.photoModel.SetCamDistanceScale,T.photoModel,.78) end; if T.photoModel.SetFacing then pcall(T.photoModel.SetFacing,T.photoModel,0) end; T:SetPhotoAnimation(0,"Idle") end)
    local hide=button(c,"HIDE CONTROLS",234,30); hide:SetPoint("TOPLEFT",15,toolsY-116); hide:SetScript("OnClick",function() T:SetPhotoControlsVisible(false) end)
    local capture=button(c,"TAKE PHOTO",234,36); capture:SetPoint("TOPLEFT",15,toolsY-158); skin(capture,{0.19,0.055,0.018,.98},C.gold,2); capture:SetScript("OnClick",function() T:CapturePhoto() end)

    local show=button(p,"SHOW CONTROLS",130,28); p.showControls=show; show:SetPoint("BOTTOMRIGHT",-24,24); show:SetScript("OnClick",function() T:SetPhotoControlsVisible(true) end); show:Hide()
    c:HookScript("OnHide",function() if p:IsShown() then show:Show() end end)
    c:HookScript("OnShow",function() show:Hide() end)

    self.state.photoAnimation=0; self.state.photoZoom=.78; self.state.photoControlsVisible=true; self.state.photoSheathed=true
    local savedBG=(self.db and self.db.profile and self.db.profile.photo and self.db.profile.photo.background) or "woodland"
    self:SetPhotoBackground(savedBG,false)
end

function T:EnterPhotoMode()
    self:EnsureUI(); if not self.photoMode then self:CreatePhotoMode() end
    if not self.photoMode then return end
    self.state.photoMode=true
    if self.main then self.main:Hide() end
    if self.tracker then self.tracker:Hide() end
    -- A transparent Blizzard transmog frame can still leak its model viewports
    -- on Classic while a vendor session is active. Keep the session alive but
    -- isolate the stock frame for the duration of Photo Mode.
    if self.state.vendorOpen and self.SetPhotoVendorIsolation then self:SetPhotoVendorIsolation(true) end
    self.photoMode:Show(); self:SetPhotoControlsVisible(true); self:RefreshPhotoModel(); self:SetPhotoAnimation(self.state.photoAnimation or 0,"Idle")
end

function T:ExitPhotoMode()
    self.state.photoMode=false
    if self.photoMode then self.photoMode:Hide() end
    if self.SetPhotoVendorIsolation then self:SetPhotoVendorIsolation(false) end
    if self.main then self.main:Show(); if self.RefreshAll then self:RefreshAll() end end
end

function T:TogglePhotoMode()
    if self.state.photoMode then self:ExitPhotoMode() else self:EnterPhotoMode() end
end
