-- =============================================================================
-- CustomSetExport.lua
-- Sends an ETB curated set into Blizzard's NATIVE Custom Sets (patch 5.5.4+).
--
-- Background: the 5.5.4 (Siege of Orgrimmar) client replaced MoP Classic's old
-- transmog system with the modern retail Wardrobe. The standalone apply API
-- (C_Transmog.SetPending / ApplyAllPending) is gone, but C_TransmogCollection's
-- Custom Sets API is fully present and natively applies incomplete sets (owned
-- pieces on, the rest skipped). So instead of maintaining our own apply UI, we
-- translate an ETB set into a Blizzard custom set and let the native window
-- apply it.
--
-- Confirmed pipeline (live):
--   info = CreateAndInitFromMixin(ItemTransmogInfoMixin, sourceID, 0, 0)
--   setID = C_TransmogCollection.NewCustomSet(name, icon, slotIndexedInfoList)
--   appearanceID field on the info == the transmog SOURCE id.
--   appearanceID 0 == empty slot (this is the incomplete-set mechanism).
-- =============================================================================

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

local CustomSetExport = {}
ETB.CustomSetExport = CustomSetExport

local NAME_PREFIX  = "ETB: "
local DEFAULT_ICON = 134400        -- inv_misc_questionmark (used by the confirmed test)
local MAX_SLOT     = 19            -- native custom-set lists span slots 1..19

-- -----------------------------------------------------------------------------
-- ItemTransmogInfo construction (robust across constructor forms)
-- -----------------------------------------------------------------------------
local function mkInfo(sourceID)
    sourceID = tonumber(sourceID) or 0
    if TransmogUtil and TransmogUtil.CreateItemTransmogInfo then
        local ok, info = pcall(TransmogUtil.CreateItemTransmogInfo, sourceID)
        if ok and info then return info end
    end
    if CreateAndInitFromMixin and ItemTransmogInfoMixin then
        local ok, info = pcall(CreateAndInitFromMixin, ItemTransmogInfoMixin, sourceID, 0, 0)
        if ok and info then return info end
    end
    return nil
end

-- Resolve a single set piece into a transmog source id.
--   community sets store  [slot] = { itemID, sourceID }
--   ETB custom sets store [slot] = itemID
--   blizzard sets may give [slot] = { itemID=, sourceID=, name= }
local function resolveSourceID(piece)
    if type(piece) == "table" then
        local sid = piece.sourceID or piece[2]
        if sid then return tonumber(sid) end
        local iid = piece.itemID or piece[1]
        if iid and ETB.CollectionAPI and ETB.CollectionAPI.GetAppearance then
            local _, sourceID = ETB.CollectionAPI:GetAppearance(iid)
            return sourceID and tonumber(sourceID) or nil
        end
        return nil
    elseif type(piece) == "number" then
        if ETB.CollectionAPI and ETB.CollectionAPI.GetAppearance then
            local _, sourceID = ETB.CollectionAPI:GetAppearance(piece)
            return sourceID and tonumber(sourceID) or nil
        end
    end
    return nil
end

-- Best-effort icon: the first defined piece's item icon, else default.
local function pickIcon(items)
    if type(items) == "table" then
        for _, piece in pairs(items) do
            local iid
            if type(piece) == "table" then
                iid = piece.itemID or piece[1]
            elseif type(piece) == "number" then
                iid = piece
            end
            if iid then
                local icon = GetItemIcon and GetItemIcon(iid)
                if icon then return icon end
            end
        end
    end
    return DEFAULT_ICON
end

-- -----------------------------------------------------------------------------
-- Public: availability + list construction
-- -----------------------------------------------------------------------------
function CustomSetExport:IsAvailable()
    return C_TransmogCollection ~= nil and type(C_TransmogCollection.NewCustomSet) == "function"
end

-- items table { [slot] = itemID | {itemID,sourceID} | {itemID=,sourceID=} }
-- -> slot-indexed list of ItemTransmogInfo (empty slots = appearanceID 0).
function CustomSetExport:BuildList(items)
    local list = {}
    for slot = 1, MAX_SLOT do
        list[slot] = mkInfo(0)
    end
    if type(items) ~= "table" then return list end
    for slot, piece in pairs(items) do
        local s = tonumber(slot)
        if s and s >= 1 and s <= MAX_SLOT then
            local sourceID = resolveSourceID(piece)
            if sourceID and sourceID > 0 then
                local info = mkInfo(sourceID)
                if info then list[s] = info end
            end
        end
    end
    return list
end

-- Find an existing ETB-created custom set by its full name; returns setID or nil.
function CustomSetExport:FindByName(fullName)
    if not (C_TransmogCollection.GetCustomSets and C_TransmogCollection.GetCustomSetInfo) then
        return nil
    end
    local sets = C_TransmogCollection.GetCustomSets() or {}
    for _, setID in ipairs(sets) do
        local ok, n = pcall(C_TransmogCollection.GetCustomSetInfo, setID)
        if ok and n == fullName then return setID end
    end
    return nil
end

-- -----------------------------------------------------------------------------
-- Public: export
-- -----------------------------------------------------------------------------
function CustomSetExport:Export(name, items, icon)
    if not self:IsAvailable() then
        print("|cff66ccffETB|r: This game version doesn't expose Blizzard's custom-set API, so the set can't be sent.")
        return nil
    end
    if type(items) ~= "table" or next(items) == nil then
        print("|cff66ccffETB|r: That set has no appearance data to send.")
        return nil
    end

    local fullName = NAME_PREFIX .. (name or "Set")
    local list     = self:BuildList(items)
    icon = icon or pickIcon(items)

    -- Overwrite any earlier export of the same set (reuse the slot, stay tidy).
    local existing = self:FindByName(fullName)
    if existing and C_TransmogCollection.DeleteCustomSet then
        pcall(C_TransmogCollection.DeleteCustomSet, existing)
    end

    -- Respect the cap.
    local sets = C_TransmogCollection.GetCustomSets() or {}
    local maxN = (C_TransmogCollection.GetNumMaxCustomSets and C_TransmogCollection.GetNumMaxCustomSets()) or 25
    if #sets >= maxN then
        print(string.format("|cff66ccffETB|r: Your Blizzard Custom Sets are full (%d/%d). Delete one in the Custom Sets tab to make room.", #sets, maxN))
        return nil
    end

    local ok, setID = pcall(C_TransmogCollection.NewCustomSet, fullName, icon, list)
    if not ok or not setID then
        print("|cff66ccffETB|r: Couldn't create the custom set" .. (type(setID) == "string" and (": " .. setID) or "."))
        return nil
    end

    print(string.format("|cff66ccffETB|r: Sent |cffffd100%s|r to your Blizzard Custom Sets. Open the |cffffd100Custom Sets|r tab at a transmogrifier to apply it (owned pieces apply, the rest are skipped).", fullName))
    self:OpenCustomSetsTab()
    return setID
end

-- Resolve an ETB selectedSetID into (name, items) using the same dispatch as SelectSet.
function CustomSetExport:ResolveSet(setID)
    if setID == nil then return nil, nil end
    if type(setID) == "string" then
        if setID:find("^COMMUNITY_") and ETB.CommunitySets and ETB.CommunitySets.GetSet then
            local s = ETB.CommunitySets:GetSet(setID)
            if s then return s.name, s.items end
        elseif (setID:find("^CUSTOM_") or setID:find("^USER_") or setID:find("^SB_")) and ETB.CustomSets then
            local items, nm
            if ETB.CustomSets.GetSet then
                local s = ETB.CustomSets:GetSet(setID)
                if s then nm = s.name; items = s.items end
            end
            if (not items) and ETB.CustomSets.GetSetItems then
                items = ETB.CustomSets:GetSetItems(setID)
            end
            return nm or "Custom Set", items
        end
    else
        local nm, items
        if ETB.SetsData and ETB.SetsData.GetSetInfo then
            local info = ETB.SetsData:GetSetInfo(setID)
            if info then nm = info.name or info.setName end
        end
        if ETB.SetsData and ETB.SetsData.GetSetItems then
            items = ETB.SetsData:GetSetItems(setID)
        end
        return nm or "Set", items
    end
    return nil, nil
end

-- Convenience entry point for the UI button (owner.selectedSetID drives it).
function CustomSetExport:ExportBySelectedID(owner)
    local setID = owner and owner.selectedSetID
    if not setID then
        print("|cff66ccffETB|r: Select a set first, then send it.")
        return nil
    end
    local name, items = self:ResolveSet(setID)
    if type(items) ~= "table" then
        print("|cff66ccffETB|r: Couldn't read that set's pieces to send.")
        return nil
    end
    return self:Export(name, items)
end

-- Best-effort: make sure the collections/transmog UI is loaded so the player
-- can switch to the Custom Sets tab. We deliberately don't force-show a
-- protected frame (taint risk); a printed nudge plus a loaded UI is enough.
function CustomSetExport:OpenCustomSetsTab()
    if Transmog_LoadUI then pcall(Transmog_LoadUI) end
end
