local AUCTION_OPCODE = 217

local window = nil
local currentTab = 'browse'
local currentPage = 1
local historyPage = 1
local currentFilters = {}
local sellPreviewData = nil
local auctionCategories = {}

function init()
  connect(g_game, {
    onGameStart = create,
    onGameEnd = destroy
  })
  ProtocolGame.registerExtendedJSONOpcode(AUCTION_OPCODE, parseOpcode)
end

function terminate()
  disconnect(g_game, {
    onGameEnd = destroy
  })
  ProtocolGame.unregisterExtendedJSONOpcode(AUCTION_OPCODE)
  destroy()
end

function create()
  -- nothing to do on game start, window created on demand
end

function destroy()
  if window then
    window:destroy()
    window = nil
  end
  sellPreviewData = nil
  currentTab = 'browse'
  currentPage = 1
  currentFilters = {}
end

function parseOpcode(protocol, opcode, data)
  if data.action == "open" then
    showWindow(data)
  elseif data.action == "browse_data" then
    populateBrowse(data)
  elseif data.action == "myoffers_data" then
    populateMyOffers(data)
  elseif data.action == "history_data" then
    populateHistory(data)
  elseif data.action == "sell_preview" then
    showSellPreview(data)
  elseif data.action == "message" then
    showMessage(data.message, data.color)
    if data.clearPreview then
      clearSellPreview()
    end
  end
end

function sendOpcode(data)
  local protocolGame = g_game.getProtocolGame()
  if protocolGame then
    protocolGame:sendExtendedJSONOpcode(AUCTION_OPCODE, data)
  end
end

-- Format gold with commas
function formatGold(amount)
  local formatted = tostring(amount)
  local k
  while true do
    formatted, k = string.gsub(formatted, "^(-?%d+)(%d%d%d)", '%1,%2')
    if k == 0 then break end
  end
  return formatted
end

-- Format time remaining
function formatTimeRemaining(expiresAt)
  local now = os.time()
  local diff = expiresAt - now
  if diff <= 0 then
    return "Expired"
  end

  local days = math.floor(diff / 86400)
  local hours = math.floor((diff % 86400) / 3600)

  if days > 0 then
    return days .. "d " .. hours .. "h left"
  elseif hours > 0 then
    return hours .. "h left"
  else
    local minutes = math.floor((diff % 3600) / 60)
    return minutes .. "m left"
  end
end

-- Show/create main window
function showWindow(data)
  if window then
    window:show()
    window:raise()
    window:focus()
  else
    window = g_ui.displayUI('auction')
    if not window then return end

    -- Setup navigation buttons (bottom bar, like market style)
    window:getChildById('browseButton').onClick = function() switchTab('browse') end
    window:getChildById('sellButton2').onClick = function() switchTab('sell') end
    window:getChildById('myOffersButton').onClick = function() switchTab('myoffers') end

    -- Setup filter buttons
    local browseTab = window:getChildById('browseTab')
    browseTab:getChildById('searchButton').onClick = onSearchClick
    local pagePanel = browseTab:getChildById('pagePanel')
    pagePanel:getChildById('prevButton').onClick = onPrevPage
    pagePanel:getChildById('nextButton').onClick = onNextPage

    -- Setup history pagination
    local myOffersTab = window:getChildById('myOffersTab')
    local historyPagePanel = myOffersTab:getChildById('historyPagePanel')
    historyPagePanel:getChildById('historyPrevButton').onClick = function()
      if historyPage > 1 then
        historyPage = historyPage - 1
        sendOpcode({action = "history", page = historyPage})
      end
    end
    historyPagePanel:getChildById('historyNextButton').onClick = function()
      historyPage = historyPage + 1
      sendOpcode({action = "history", page = historyPage})
    end

    -- Fix focus on all TextEdit inputs (re-focus window when clicked after chat steals focus)
    local focusFix = function() window:focus() return false end
    connect(browseTab:getChildById('searchInput'), { onMousePress = focusFix })
    connect(browseTab:getChildById('priceMinInput'), { onMousePress = focusFix })
    connect(browseTab:getChildById('priceMaxInput'), { onMousePress = focusFix })

    -- Setup sell tab
    local sellTab = window:getChildById('sellTab')
    local sellItemWidget = sellTab:getChildById('sellItemWidget')

    -- Override onDrop to capture source container/slot before the item is set
    sellItemWidget.onDrop = function(self, widget, mousePos)
      if not widget or not widget.currentDragThing then
        return false
      end

      local item = widget.currentDragThing
      if not item or not item:isItem() or not item:isPickupable() then
        return false
      end

      local itemPos = item:getPosition()
      if not itemPos or itemPos.x ~= 65535 then
        -- Only accept items from inventory/containers (x=0xFFFF), not from ground
        return false
      end

      -- Set the visual item
      self:setItem(Item.create(item:getId(), item:getCountOrSubType()))
      UIDragIcon:hide()

      -- Detect if from equipment slot or container
      if itemPos.y < 64 then
        -- Equipment slot (y = slot ID: 1-10)
        sendOpcode({action = "sell_preview", fromSlot = itemPos.y})
      else
        -- Container item (y = 64 + containerId, z = slot)
        local containerId = itemPos.y - 64
        local slot = itemPos.z
        sendOpcode({action = "sell_preview", containerId = containerId, slot = slot})
      end

      return true
    end

    sellTab:getChildById('sellButton').onClick = onSellConfirm
    local priceInput = sellTab:getChildById('sellPricePanel'):getChildById('priceInput')
    priceInput.onTextChange = onPriceChange
    connect(priceInput, { onMousePress = focusFix })
    local quantityInput = sellTab:getChildById('sellPricePanel'):getChildById('quantityInput')
    connect(quantityInput, { onMousePress = focusFix })

    -- Setup category filter
    local categoryFilter = browseTab:getChildById('categoryFilter')
    categoryFilter:addOption('All Categories', 'all')
    if data.categories then
      auctionCategories = data.categories
      for key, name in pairs(data.categories) do
        categoryFilter:addOption(name, key)
      end
    end

    -- Setup rarity filter
    local rarityFilter = browseTab:getChildById('rarityFilter')
    rarityFilter:addOption('All Rarity', 'all')
    rarityFilter:addOption('Common', 'common')
    rarityFilter:addOption('Rare', 'rare')
    rarityFilter:addOption('Epic', 'epic')
    rarityFilter:addOption('Legendary', 'legendary')
  end

  -- Update balance
  if data.balance then
    window:getChildById('balanceLabel'):setText('Balance: ' .. formatGold(data.balance) .. ' gps')
  end

  -- Request browse data
  switchTab('browse')
  window:raise()
  window:focus()
end

function hideWindow()
  if window then
    clearSellPreview()

    -- Clear filters
    local browseTab = window:getChildById('browseTab')
    browseTab:getChildById('searchInput'):setText('')
    browseTab:getChildById('priceMinInput'):setText('')
    browseTab:getChildById('priceMaxInput'):setText('')
    browseTab:getChildById('categoryFilter'):setCurrentIndex(1)
    browseTab:getChildById('rarityFilter'):setCurrentIndex(1)

    -- Clear sell price
    local sellTab = window:getChildById('sellTab')
    sellTab:getChildById('sellPricePanel'):getChildById('priceInput'):setText('')

    currentPage = 1
    historyPage = 1
    currentFilters = {}
    switchTab('browse')
    window:hide()
  end
end

-- Tab switching
function switchTab(tab)
  if not window then return end
  currentTab = tab

  window:getChildById('browseTab'):setVisible(tab == 'browse')
  window:getChildById('sellTab'):setVisible(tab == 'sell')
  window:getChildById('myOffersTab'):setVisible(tab == 'myoffers')

  if tab == 'browse' then
    currentPage = 1
    onSearchClick()
  elseif tab == 'myoffers' then
    sendOpcode({action = "myoffers"})
    sendOpcode({action = "history"})
  end
end

-- Browse tab functions
function onSearchClick()
  if not window then return end
  local browseTab = window:getChildById('browseTab')

  local categoryFilter = browseTab:getChildById('categoryFilter')
  local rarityFilter = browseTab:getChildById('rarityFilter')
  local priceMin = tonumber(browseTab:getChildById('priceMinInput'):getText()) or 0
  local priceMax = tonumber(browseTab:getChildById('priceMaxInput'):getText()) or 0
  local search = browseTab:getChildById('searchInput'):getText()

  currentFilters = {
    category = categoryFilter:getCurrentOption().data or 'all',
    rarity = rarityFilter:getCurrentOption().data or 'all',
    priceMin = priceMin,
    priceMax = priceMax,
    search = search,
    page = currentPage,
  }

  sendOpcode({action = "browse", filters = currentFilters})
end

function onPrevPage()
  if currentPage > 1 then
    currentPage = currentPage - 1
    onSearchClick()
  end
end

function onNextPage()
  currentPage = currentPage + 1
  onSearchClick()
end

function populateBrowse(data)
  if not window then return end
  local browseTab = window:getChildById('browseTab')
  local offersList = browseTab:getChildById('offersList')
  offersList:destroyChildren()

  -- Update balance
  if data.balance then
    window:getChildById('balanceLabel'):setText('Balance: ' .. formatGold(data.balance) .. ' gps')
  end

  -- Update pagination
  local pagePanel = browseTab:getChildById('pagePanel')
  local pageLabel = pagePanel:getChildById('pageLabel')
  local prevButton = pagePanel:getChildById('prevButton')
  local nextButton = pagePanel:getChildById('nextButton')

  currentPage = data.page or 1
  local totalPages = data.totalPages or 1

  pageLabel:setText('Page ' .. currentPage .. '/' .. totalPages)
  prevButton:setEnabled(currentPage > 1)
  nextButton:setEnabled(currentPage < totalPages)

  if not data.offers then return end

  for _, offer in ipairs(data.offers) do
    local widget = g_ui.createWidget('AuctionOfferItem', offersList)

    -- Set item sprite
    local itemWidget = widget:getChildById('itemWidget')
    if offer.clientId and offer.clientId > 0 then
      itemWidget:setItemId(offer.clientId)
      if offer.count and offer.count > 1 then
        itemWidget:setItemCount(offer.count)
      end
    end

    -- Apply rarity overlay
    if offer.rarity and offer.rarity ~= 'common' and ItemsDatabase and ItemsDatabase.applyRarityOverlay then
      ItemsDatabase.applyRarityOverlay(itemWidget, offer.rarity)
    end

    -- Set labels
    widget:getChildById('nameLabel'):setText(offer.itemName or 'Unknown')
    widget:getChildById('priceLabel'):setText(formatGold(offer.price or 0) .. ' gps')
    widget:getChildById('sellerLabel'):setText(offer.sellerName or '')
    widget:getChildById('timeLabel'):setText(formatTimeRemaining(offer.expiresAt or 0))

    -- Tooltip with full description
    if offer.fullDescription and offer.fullDescription ~= '' then
      widget:setTooltip(offer.fullDescription)
    end

    -- Buy button
    local buyButton = widget:getChildById('buyButton')
    buyButton.onClick = function()
      onBuyClick(offer.id, offer.itemName, offer.price)
    end
  end
end

function onBuyClick(offerId, itemName, price)
  local confirmWindow
  local function onYes()
    sendOpcode({action = "buy", offerId = offerId})
    confirmWindow:destroy()
    confirmWindow = nil
  end
  local function onNo()
    confirmWindow:destroy()
    confirmWindow = nil
  end
  confirmWindow = displayGeneralBox(
    'Confirm Purchase',
    'Buy ' .. (itemName or 'item') .. ' for ' .. formatGold(price or 0) .. ' gps?',
    {
      {text = 'Yes', callback = onYes},
      {text = 'No', callback = onNo},
      anchor = AnchorHorizontalCenter
    }
  )
end

-- Sell tab functions
function showSellPreview(data)
  if not window then return end
  sellPreviewData = data

  local sellTab = window:getChildById('sellTab')

  -- Update item widget
  local itemWidget = sellTab:getChildById('sellItemWidget')
  if data.clientId and data.clientId > 0 then
    itemWidget:setItemId(data.clientId)
    if data.count and data.count > 1 then
      itemWidget:setItemCount(data.count)
    end
  end

  -- Apply or clear rarity overlay
  if ItemsDatabase and ItemsDatabase.applyRarityOverlay then
    local rarity = data.rarity
    if rarity == 'common' then rarity = nil end
    ItemsDatabase.applyRarityOverlay(itemWidget, rarity)
  end

  -- Show full description
  local descLabel = sellTab:getChildById('sellDescLabel')
  descLabel:setText(data.fullDescription or '')

  -- Show quantity input for stackable items (count > 1)
  local sellPricePanel = sellTab:getChildById('sellPricePanel')
  local isStackable = data.count and data.count > 1
  sellPricePanel:getChildById('quantityLabel'):setVisible(isStackable)
  sellPricePanel:getChildById('quantityInput'):setVisible(isStackable)
  sellPricePanel:getChildById('quantityMax'):setVisible(isStackable)
  if isStackable then
    sellPricePanel:getChildById('quantityInput'):setText(tostring(data.count))
    sellPricePanel:getChildById('quantityMax'):setText('/ ' .. data.count)
  end

  -- Enable sell button
  sellTab:getChildById('sellButton'):setEnabled(true)

  -- Update instructions
  sellTab:getChildById('sellInstructions'):setText(data.name or 'Item')
end

function clearSellPreview()
  if not window then return end
  sellPreviewData = nil

  local sellTab = window:getChildById('sellTab')
  local itemWidget = sellTab:getChildById('sellItemWidget')
  itemWidget:clearItem()

  -- Remove rarity overlay if present
  if ItemsDatabase and ItemsDatabase.applyRarityOverlay then
    ItemsDatabase.applyRarityOverlay(itemWidget, nil)
  end
  local rarityOverlay = itemWidget:getChildById('rarityOverlay')
  if rarityOverlay then
    rarityOverlay:setVisible(false)
  end

  sellTab:getChildById('sellDescLabel'):setText('')
  sellTab:getChildById('sellButton'):setEnabled(false)
  sellTab:getChildById('sellInstructions'):setText('Drag an item from your inventory to sell it')

  -- Hide quantity controls
  local sellPricePanel = sellTab:getChildById('sellPricePanel')
  sellPricePanel:getChildById('quantityLabel'):setVisible(false)
  sellPricePanel:getChildById('quantityInput'):setVisible(false)
  sellPricePanel:getChildById('quantityMax'):setVisible(false)

  local sellInfoLabel = sellTab:getChildById('sellInfoLabel')
  sellInfoLabel:setText('')
end

function onPriceChange(widget, text)
  if not window then return end
  local price = tonumber(text) or 0
  local sellTab = window:getChildById('sellTab')
  local feeLabel = sellTab:getChildById('sellPricePanel'):getChildById('feeLabel')

  if price > 0 then
    local fee = math.max(math.floor(price * 2 / 100), 100)
    feeLabel:setText('Listing fee: ' .. formatGold(fee) .. ' gps')
  else
    feeLabel:setText('Listing fee: 0 gps')
  end
end

function onSellConfirm()
  if not window or not sellPreviewData then return end

  local sellTab = window:getChildById('sellTab')
  local sellPricePanel = sellTab:getChildById('sellPricePanel')
  local priceInput = sellPricePanel:getChildById('priceInput')
  local price = tonumber(priceInput:getText()) or 0

  -- Get quantity for stackable items
  local quantity = sellPreviewData.count or 1
  local quantityInput = sellPricePanel:getChildById('quantityInput')
  if quantityInput:isVisible() then
    quantity = tonumber(quantityInput:getText()) or 1
    if quantity < 1 then
      showMessage("Quantity must be at least 1.", "red")
      return
    end
    if quantity > (sellPreviewData.count or 1) then
      showMessage("You only have " .. (sellPreviewData.count or 1) .. ".", "red")
      return
    end
  end

  if price < 100 then
    showMessage("Minimum price is 100 gps.", "red")
    return
  end

  local fee = math.max(math.floor(price * 2 / 100), 100)
  local itemName = sellPreviewData.name or 'item'
  if quantity > 1 then
    itemName = quantity .. 'x ' .. itemName
  end
  local previewData = sellPreviewData
  local sellQuantity = quantity

  local confirmWindow
  local function onYes()
    sendOpcode({
      action = "create",
      fromSlot = previewData.fromSlot,
      containerId = previewData.containerId,
      slot = previewData.slot,
      price = price,
      quantity = sellQuantity,
      expectedItemId = previewData.itemId,
      expectedRarity = previewData.rarity or "common",
    })
    clearSellPreview()
    priceInput:setText('')
    confirmWindow:destroy()
    confirmWindow = nil
  end
  local function onNo()
    confirmWindow:destroy()
    confirmWindow = nil
  end
  confirmWindow = displayGeneralBox(
    'Confirm Listing',
    'List ' .. itemName .. ' for ' .. formatGold(price) .. ' gps?\nFee: ' .. formatGold(fee) .. ' gps',
    {
      {text = 'Yes', callback = onYes},
      {text = 'No', callback = onNo},
      anchor = AnchorHorizontalCenter
    }
  )
end

-- My Offers tab functions
function populateMyOffers(data)
  if not window then return end
  local myOffersTab = window:getChildById('myOffersTab')
  local myOffersList = myOffersTab:getChildById('myOffersList')
  myOffersList:destroyChildren()

  -- Update balance
  if data.balance then
    window:getChildById('balanceLabel'):setText('Balance: ' .. formatGold(data.balance) .. ' gps')
  end

  if not data.offers then return end

  for _, offer in ipairs(data.offers) do
    local widget = g_ui.createWidget('AuctionMyOfferItem', myOffersList)

    -- Set item sprite
    local itemWidget = widget:getChildById('itemWidget')
    if offer.clientId and offer.clientId > 0 then
      itemWidget:setItemId(offer.clientId)
      if offer.count and offer.count > 1 then
        itemWidget:setItemCount(offer.count)
      end
    end

    -- Apply rarity overlay
    if offer.rarity and offer.rarity ~= 'common' and ItemsDatabase and ItemsDatabase.applyRarityOverlay then
      ItemsDatabase.applyRarityOverlay(itemWidget, offer.rarity)
    end

    -- Set labels
    widget:getChildById('nameLabel'):setText(offer.itemName or 'Unknown')
    widget:getChildById('priceLabel'):setText(formatGold(offer.price or 0) .. ' gps')
    widget:getChildById('timeLabel'):setText(formatTimeRemaining(offer.expiresAt or 0))

    -- Tooltip
    if offer.fullDescription and offer.fullDescription ~= '' then
      widget:setTooltip(offer.fullDescription)
    end

    -- Edit price button
    local editButton = widget:getChildById('editButton')
    editButton.onClick = function()
      onEditPrice(offer.id, offer.price)
    end

    -- Extend button
    local extendButton = widget:getChildById('extendButton')
    extendButton.onClick = function()
      onExtendClick(offer.id, offer.price)
    end

    -- Cancel button
    local cancelButton = widget:getChildById('cancelButton')
    cancelButton.onClick = function()
      onCancelClick(offer.id, offer.itemName)
    end
  end
end

local editPriceWindow = nil

function onEditPrice(offerId, currentPrice)
  if editPriceWindow then
    editPriceWindow:destroy()
    editPriceWindow = nil
  end

  editPriceWindow = g_ui.createWidget('MainWindow', rootWidget)
  editPriceWindow:setSize({width = 280, height = 160})
  editPriceWindow:setText('Edit Price')

  local label = g_ui.createWidget('Label', editPriceWindow)
  label:setText('Current price: ' .. formatGold(currentPrice) .. ' gps')
  label:addAnchor(AnchorTop, 'parent', AnchorTop)
  label:addAnchor(AnchorLeft, 'parent', AnchorLeft)
  label:addAnchor(AnchorRight, 'parent', AnchorRight)
  label:setTextAlign(AlignCenter)
  label:setColor('#c0c0c0')
  label:setHeight(16)

  local priceLabel = g_ui.createWidget('Label', editPriceWindow)
  priceLabel:setText('New price:')
  priceLabel:addAnchor(AnchorTop, label:getId(), AnchorBottom)
  priceLabel:addAnchor(AnchorLeft, 'parent', AnchorLeft)
  priceLabel:setMarginTop(10)
  priceLabel:setWidth(70)
  priceLabel:setHeight(20)

  local priceInput = g_ui.createWidget('TextEdit', editPriceWindow)
  priceInput:setId('editPriceInput')
  priceInput:addAnchor(AnchorTop, priceLabel:getId(), AnchorTop)
  priceInput:addAnchor(AnchorLeft, priceLabel:getId(), AnchorRight)
  priceInput:addAnchor(AnchorRight, 'parent', AnchorRight)
  priceInput:setMarginLeft(5)
  priceInput:setHeight(20)

  local feeLabel = g_ui.createWidget('Label', editPriceWindow)
  feeLabel:setId('editFeeLabel')
  feeLabel:setText('Fee: 0 gps')
  feeLabel:addAnchor(AnchorTop, priceInput:getId(), AnchorBottom)
  feeLabel:addAnchor(AnchorLeft, 'parent', AnchorLeft)
  feeLabel:addAnchor(AnchorRight, 'parent', AnchorRight)
  feeLabel:setMarginTop(5)
  feeLabel:setColor('#999999')
  feeLabel:setHeight(16)
  feeLabel:setTooltip('The fee is 2% of the new price (minimum 100 gps). This fee is non-refundable.')

  connect(priceInput, { onTextChange = function(widget, text)
    local price = tonumber(text) or 0
    if price > 0 then
      local fee = math.max(math.floor(price * 2 / 100), 100)
      feeLabel:setText('Fee: ' .. formatGold(fee) .. ' gps')
    else
      feeLabel:setText('Fee: 0 gps')
    end
  end })

  local cancelBtn = g_ui.createWidget('Button', editPriceWindow)
  cancelBtn:setText('Cancel')
  cancelBtn:setWidth(65)
  cancelBtn:setHeight(20)
  cancelBtn:addAnchor(AnchorBottom, 'parent', AnchorBottom)
  cancelBtn:addAnchor(AnchorRight, 'parent', AnchorRight)
  cancelBtn.onClick = function()
    editPriceWindow:destroy()
    editPriceWindow = nil
  end

  local confirmBtn = g_ui.createWidget('Button', editPriceWindow)
  confirmBtn:setText('Confirm')
  confirmBtn:setWidth(65)
  confirmBtn:setHeight(20)
  confirmBtn:addAnchor(AnchorBottom, 'parent', AnchorBottom)
  confirmBtn:addAnchor(AnchorRight, cancelBtn:getId(), AnchorLeft)
  confirmBtn:setMarginRight(5)
  confirmBtn.onClick = function()
    local newPrice = tonumber(priceInput:getText()) or 0
    if newPrice < 100 then
      return
    end
    sendOpcode({action = "editprice", offerId = offerId, newPrice = newPrice})
    editPriceWindow:destroy()
    editPriceWindow = nil
  end

  editPriceWindow:raise()
  editPriceWindow:focus()
  priceInput:focus()
end

function onExtendClick(offerId, price)
  local fee = math.max(math.floor(price * 2 / 100), 100)
  local confirmWindow
  local function onYes()
    sendOpcode({action = "extend", offerId = offerId})
    confirmWindow:destroy()
    confirmWindow = nil
  end
  local function onNo()
    confirmWindow:destroy()
    confirmWindow = nil
  end
  confirmWindow = displayGeneralBox(
    'Extend Offer',
    'Extend this offer by 7 days?\nFee: ' .. formatGold(fee) .. ' gps',
    {
      {text = 'Yes', callback = onYes},
      {text = 'No', callback = onNo},
      anchor = AnchorHorizontalCenter
    }
  )
end

function onCancelClick(offerId, itemName)
  local confirmWindow
  local function onYes()
    sendOpcode({action = "cancel", offerId = offerId})
    confirmWindow:destroy()
    confirmWindow = nil
  end
  local function onNo()
    confirmWindow:destroy()
    confirmWindow = nil
  end
  confirmWindow = displayGeneralBox(
    'Cancel Offer',
    'Cancel listing for ' .. (itemName or 'item') .. '?\nThe item will be returned to your inbox.',
    {
      {text = 'Yes', callback = onYes},
      {text = 'No', callback = onNo},
      anchor = AnchorHorizontalCenter
    }
  )
end

-- History
function populateHistory(data)
  if not window then return end
  local myOffersTab = window:getChildById('myOffersTab')
  local historyList = myOffersTab:getChildById('historyList')
  historyList:destroyChildren()

  -- Update pagination
  local historyPagePanel = myOffersTab:getChildById('historyPagePanel')
  historyPage = data.page or 1
  local totalPages = data.totalPages or 1

  historyPagePanel:getChildById('historyPageLabel'):setText('Page ' .. historyPage .. '/' .. totalPages)
  historyPagePanel:getChildById('historyPrevButton'):setEnabled(historyPage > 1)
  historyPagePanel:getChildById('historyNextButton'):setEnabled(historyPage < totalPages)

  if not data.offers then return end

  local statusNames = {
    [1] = {text = "Sold", color = "#00cc00"},
    [2] = {text = "Cancelled", color = "#ffcc00"},
    [3] = {text = "Expired", color = "#cc0000"},
  }

  for _, offer in ipairs(data.offers) do
    local widget = g_ui.createWidget('AuctionHistoryItem', historyList)

    -- Set item sprite
    local itemWidget = widget:getChildById('itemWidget')
    if offer.clientId and offer.clientId > 0 then
      itemWidget:setItemId(offer.clientId)
      if offer.count and offer.count > 1 then
        itemWidget:setItemCount(offer.count)
      end
    end

    -- Apply rarity overlay
    if offer.rarity and offer.rarity ~= 'common' and ItemsDatabase and ItemsDatabase.applyRarityOverlay then
      ItemsDatabase.applyRarityOverlay(itemWidget, offer.rarity)
    end

    -- Set labels
    widget:getChildById('nameLabel'):setText(offer.itemName or 'Unknown')
    widget:getChildById('priceLabel'):setText(formatGold(offer.price or 0) .. ' gps')

    local status = statusNames[offer.status] or {text = "Unknown", color = "#999999"}
    local statusLabel = widget:getChildById('statusLabel')
    statusLabel:setText(status.text)
    statusLabel:setColor(status.color)

    -- Buyer name for sold items
    local buyerLabel = widget:getChildById('buyerLabel')
    if offer.status == 1 and offer.buyerName and offer.buyerName ~= '' then
      buyerLabel:setText('Buyer: ' .. offer.buyerName)
    else
      buyerLabel:setText(os.date('%Y-%m-%d', offer.createdAt or 0))
    end

    -- Tooltip with full description
    if offer.fullDescription and offer.fullDescription ~= '' then
      widget:setTooltip(offer.fullDescription)
    end
  end
end

-- Message display
function showMessage(message, color)
  if not window then return end

  -- Show as popup dialog
  local title = 'Auction House'
  if color == 'red' then
    title = 'Error'
  end
  displayInfoBox(title, message)

  -- Rarity frames are refreshed by the server after successful actions

  -- Also refresh data after action
  if currentTab == 'browse' then
    onSearchClick()
  elseif currentTab == 'myoffers' then
    sendOpcode({action = "myoffers"})
    sendOpcode({action = "history"})
  end
end
