-- =============================================================================
-- ETB v12.40.0 — TransmogUI/Preview.lua
-- =============================================================================
-- Hover preview frame: 200×300 DressUpModel shown next to the browser panel.
-- Extracted from the v12.39.0 monolithic TransmogUI.lua.
--
-- Public API:
--   Preview:Create()                    — one-time frame creation
--   Preview:Show(itemData, anchorFrame) — show preview for an item/set
--   Preview:Hide()                      — hide preview
--   Preview:GetFrame()                  — returns the underlying frame (for callers
--                                         that need to test visibility, etc.)
--
-- itemData fields consumed:
--   .itemID   — single item preview
--   .isSet + .items — set preview (items is array of itemIDs or tables w/ itemID)
--   .isHidden — skip preview (used for hidden-slot appearances)
--   .name     — title text
--   .source   — subtitle / source description
--
-- anchorFrame: the frame whose TOPRIGHT edge we anchor to. Passing this in
-- explicitly (rather than reading self.frame.browserPanel from TUI) removes
-- coupling to the parent's internal layout.
-- =============================================================================

local ADDON_NAME, NS = ...
local ETB = NS.ETB

NS.ETB.TransmogUI = NS.ETB.TransmogUI or {}
local Preview = {}
NS.ETB.TransmogUI.Preview = Preview

-- Internal state
Preview.frame = nil
Preview.currentItem = nil  -- used for the delayed-TryOn race check

-- =============================================================================
-- Frame creation (one-time)
-- =============================================================================

function Preview:Create()
    if self.frame then return self.frame end

    local f = CreateFrame("Frame", nil, UIParent, "BackdropTemplate")
    f:SetSize(200, 300)
    f:SetBackdrop({
        bgFile = "Interface\\DialogFrame\\UI-DialogBox-Background-Dark",
        edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
        tile = true, tileSize = 16, edgeSize = 12,
        insets = { left = 3, right = 3, top = 3, bottom = 3 }
    })
    f:SetFrameStrata("TOOLTIP")
    f:SetFrameLevel(200)
    f:Hide()

    -- Title at top
    f.title = f:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    f.title:SetPoint("TOP", 0, -8)
    f.title:SetWidth(185)
    f.title:SetJustifyH("CENTER")
    f.title:SetMaxLines(1)

    -- Model frame
    local model = CreateFrame("DressUpModel", nil, f)
    model:SetSize(180, 240)
    model:SetPoint("TOP", 0, -26)
    model.zoomLevel = 0
    model:EnableMouse(true)
    model:EnableMouseWheel(true)

    model:SetScript("OnMouseDown", function(self, button)
        if button == "LeftButton" then
            self.rotating = true
            self.startX = GetCursorPosition()
            self.startRotation = self:GetFacing()
        end
    end)
    model:SetScript("OnMouseUp", function(self) self.rotating = false end)
    model:SetScript("OnUpdate", function(self)
        if self.rotating then
            local x = GetCursorPosition()
            local diff = (x - (self.startX or x)) * 0.01
            self:SetFacing((self.startRotation or 0) + diff)
        end
    end)
    model:SetScript("OnMouseWheel", function(self, delta)
        self.zoomLevel = math.max(-0.5, math.min(1.5, (self.zoomLevel or 0) + delta * 0.1))
        self:SetCamDistanceScale(1 - self.zoomLevel)
    end)

    model:SetPortraitZoom(0)
    model:SetCamDistanceScale(1.0)
    model:SetPosition(0, 0, -0.15)

    f.model = model
    model:SetUnit("player")

    -- Source label at bottom
    f.label = f:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
    f.label:SetPoint("BOTTOM", 0, 6)
    f.label:SetWidth(185)
    f.label:SetJustifyH("CENTER")
    f.label:SetTextColor(0.5, 0.5, 0.5)

    self.frame = f
    return f
end

-- =============================================================================
-- Show / Hide
-- =============================================================================

function Preview:Show(itemData, anchorFrame)
    if not itemData then return end
    if not itemData.itemID and not (itemData.isSet and itemData.items) and not itemData.isHidden then return end
    if itemData.isHidden then return end  -- No preview for hidden slots

    -- Lazy-create on first show
    if not self.frame then self:Create() end
    local f = self.frame
    self.currentItem = itemData

    -- Anchor to right edge of the passed-in anchor frame (typically the
    -- browser panel). Falls back to UIParent center if no anchor given.
    f:ClearAllPoints()
    if anchorFrame then
        f:SetPoint("TOPLEFT", anchorFrame, "TOPRIGHT", 4, 0)
    else
        f:SetPoint("CENTER", UIParent, "CENTER")
    end

    -- Reset model
    f.model:Dress()
    f.model:Undress()
    f.model:SetRotation(0)
    f.model:SetPosition(0, 0, -0.15)

    -- Title
    if itemData.isSet then
        f.title:SetText("|cffffd100" .. (itemData.name or "Set") .. "|r")
    else
        f.title:SetText(itemData.name or "Preview")
    end

    -- Source label
    f.label:SetText(itemData.source and ("|cff666666" .. itemData.source .. "|r") or "")

    f:Show()

    -- Delayed TryOn — gives the model a frame to initialize. Capture the
    -- current itemData so that rapid mouseovers don't TryOn a stale item.
    local captured = itemData
    local self_ = self  -- avoid confusion with C_Timer's self
    C_Timer.After(0.05, function()
        if self_.currentItem ~= captured then return end
        if not f:IsShown() then return end

        if captured.itemID then
            -- Single item preview
            pcall(function() f.model:TryOn("item:" .. captured.itemID) end)
        elseif captured.isSet and captured.items then
            -- Set preview: try on all items
            for _, itemEntry in pairs(captured.items) do
                local itemID
                if type(itemEntry) == "number" then
                    itemID = itemEntry
                elseif type(itemEntry) == "table" then
                    itemID = itemEntry.itemID or itemEntry[1]
                end
                if itemID and type(itemID) == "number" then
                    pcall(function() f.model:TryOn("item:" .. itemID) end)
                end
            end
        end
    end)
end

function Preview:Hide()
    self.currentItem = nil  -- clear for race check
    if self.frame then
        self.frame:Hide()
    end
end

function Preview:GetFrame()
    return self.frame
end
