-- VDS.AuctionatorBridge
-- ============================================================================
-- Send-to-AH boundary. Calls Auctionator.API.v1.CreateShoppingList with the
-- cart expressed as search strings. Auctionator is a soft dependency: missing
-- addon -> friendly print, no error.
--
-- Cart source: deficit selectors (stock.buy.cart / stock.herbs.list). No
-- persisted cart state -- every click recomputes from current target/owned.
-- CreateShoppingList with the same listName REPLACES the Auctionator list,
-- so the AH side always mirrors the current deficit.
--
-- Wire format: api.CreateShoppingList(callerID, listName, searchStrings) where
-- each entry is either a plain item name (legacy) or api.ConvertToSearchString
-- output (newer builds carry exact-match + quantity).
--
-- OWNS:       Auctionator.API.v1.* (third-party, gated by IsAddOnLoaded)
-- FORBIDDEN:  any other file calling Auctionator directly.

VDS = VDS or {}

local CALLER_ID = "VamoosesDyeStudio"

local function getApi()
    if not _G.C_AddOns.IsAddOnLoaded("Auctionator") then
        return nil, "Auctionator is not loaded"
    end
    local A = _G.Auctionator and _G.Auctionator.API and _G.Auctionator.API.v1  -- exception(boundary): Auctionator optional addon
    if not (A and A.CreateShoppingList) then  -- exception(boundary): Auctionator API surface varies by version
        return nil, "Auctionator API v1.CreateShoppingList is not available"
    end
    return A
end

-- Cache-first name lookup. Returns nil on miss; caller Requests + skips.
-- `""` is treated as a miss at BOTH layers: the cache CAN hold an empty string
-- (resolver race), and C_Item.GetItemNameByID can return `""` for items that
-- aren't fully loaded into the client cache. Lua's `""` is truthy, so a naive
-- `if name then` downstream would ship `\" Dye\"` as the search string.
local function resolveItemName(itemID)
    if not itemID then return nil end
    local cached = VDS.Store:GetState().session.items.names[itemID]
    if cached and cached ~= "" then return cached end
    local raw = _G.C_Item.GetItemNameByID(itemID)  -- boundary
    if raw and raw ~= "" then return raw end
    return nil
end

-- Build search-string array straight from deficit selectors. Buy ships dyes,
-- Craft ships herbs. The list name (VDS-Dyes / VDS-Herbs) keeps the two lists
-- coexisting in Auctionator. Returns (searchStrings, missing, totalQty).
local function buildSearchStrings(api, hasQty)
    local out, missing, totalQty = {}, 0, 0
    local state = VDS.Store:GetState()
    local mode  = state.account.warehouse.fillMode

    if mode == "buy" then
        for _, item in ipairs(VDS.Selectors:Call("stock.buy.cart", state, {})) do
            local name = resolveItemName(item.itemID) or item.name
            if name then
                -- C_DyeColor names sometimes omit the " Dye" suffix that the
                -- item listing carries; pad so the AH search matches.
                if not name:find("Dye") then name = name .. " Dye" end
                out[#out + 1] = hasQty
                    and api.ConvertToSearchString(CALLER_ID, { searchString = name, isExact = true, quantity = item.qty })
                    or  name
                totalQty = totalQty + item.qty
            else
                missing = missing + 1
                if item.itemID then VDS.ItemNameResolver:Request(item.itemID) end
            end
        end
    elseif mode == "craft" then
        for _, h in ipairs(VDS.Selectors:Call("stock.herbs.list", state, {})) do
            local name = resolveItemName(h.itemID)
            if name then
                out[#out + 1] = hasQty
                    and api.ConvertToSearchString(CALLER_ID, { searchString = name, isExact = true, quantity = h.qty })
                    or  name
                totalQty = totalQty + h.qty
            else
                missing = missing + 1
                VDS.ItemNameResolver:Request(h.itemID)
            end
        end
    end

    return out, missing, totalQty
end

-- ===== Module registration ==================================================
VDS.Modules:Declare({
    name = "AuctionatorBridge",
    dependencies = {},
    ownsBlizzardNamespaces = { "Auctionator" },  -- third-party addon

    SendCart = function(self)
        local api, err = getApi()
        if not api then
            print(VDS.Constants.CHAT_PREFIX .. " " .. err ..
                  ". Install Auctionator from CurseForge to enable Send to AH.")
            return false
        end

        local hasQty = api.ConvertToSearchString ~= nil
        local searchStrings, missing, totalQty = buildSearchStrings(api, hasQty)

        if #searchStrings == 0 then
            if missing > 0 then
                print(VDS.Constants.CHAT_PREFIX .. " " .. missing .. " item name(s) still "
                      .. "loading. Try Send to AH again in a moment.")
            else
                print(VDS.Constants.CHAT_PREFIX .. " Nothing to buy -- all at target. "
                      .. "Auctionator list unchanged.")
            end
            return false
        end

        local fillMode = VDS.Store:GetState().account.warehouse.fillMode
        local listName = fillMode == "craft" and "VDS-Herbs" or "VDS-Dyes"
        api.CreateShoppingList(CALLER_ID, listName, searchStrings)

        local kindWord    = (fillMode == "craft") and "herb kinds" or "dye kinds"
        local totalWord   = (fillMode == "craft") and "herbs total" or "dyes total"
        local missingText = missing > 0 and (" -- " .. missing .. " skipped (name unresolved)") or ""
        print(VDS.Constants.CHAT_PREFIX .. " Sent " .. #searchStrings .. " " .. kindWord
              .. " (" .. totalQty .. " " .. totalWord .. ") to Auctionator list: "
              .. listName .. missingText)
        return true
    end,
})
