--------------------------------------------------------------------------------
-- Nanami-UI: Merchant UI (Merchant.lua)
-- Replaces MerchantFrame with Nanami-UI styled interface
-- Tabs: Merchant / Buyback, 4x5 grid, batch buy, repair
--------------------------------------------------------------------------------

SFrames = SFrames or {}
SFrames.Merchant = {}
local MUI = SFrames.Merchant
SFramesDB = SFramesDB or {}

--------------------------------------------------------------------------------
-- Theme (Pink Cat-Paw)
--------------------------------------------------------------------------------
local T = SFrames.Theme:Extend({
    moneyGold   = { 1, 0.84, 0.0 },
    moneySilver = { 0.78, 0.78, 0.78 },
    moneyCopper = { 0.71, 0.43, 0.18 },
    cantAfford  = { 0.80, 0.20, 0.20 },
    unusable    = { 1.00, 0.25, 0.25 },
})

local QUALITY_COLORS = {
    [0] = { 0.62, 0.62, 0.62 }, [1] = { 1, 1, 1 },
    [2] = { 0.12, 1, 0 },       [3] = { 0.0, 0.44, 0.87 },
    [4] = { 0.64, 0.21, 0.93 }, [5] = { 1, 0.5, 0 },
}

--------------------------------------------------------------------------------
-- Layout
--------------------------------------------------------------------------------
local NUM_COLS      = 4
local NUM_ROWS      = 5
local ITEMS_PER_PAGE = NUM_COLS * NUM_ROWS
local FRAME_W       = 620
local HEADER_H      = 34
local SIDE_PAD      = 14
local ITEM_W        = 138
local ITEM_H        = 42
local ITEM_GAP_X    = 6
local ITEM_GAP_Y    = 4
local ICON_SIZE     = 34
local BOTTOM_H      = 50
local TAB_AREA_H    = 28
local FRAME_H       = HEADER_H + 6 + TAB_AREA_H + (ITEM_H + ITEM_GAP_Y) * NUM_ROWS + 6 + BOTTOM_H

--------------------------------------------------------------------------------
-- State
--------------------------------------------------------------------------------
local MainFrame     = nil
local ItemButtons   = {}
local CurrentPage   = 1
local CurrentTab    = 1
local BuyPopup      = nil
local ScanTip       = nil

--------------------------------------------------------------------------------
-- Helpers
--------------------------------------------------------------------------------
local function GetFont()
    if SFrames and SFrames.GetFont then return SFrames:GetFont() end
    return "Fonts\\ARIALN.TTF"
end

local function SetRoundBackdrop(frame)
    frame:SetBackdrop({
        bgFile   = "Interface\\Tooltips\\UI-Tooltip-Background",
        edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
        tile = true, tileSize = 16, edgeSize = 14,
        insets = { left = 3, right = 3, top = 3, bottom = 3 },
    })
    frame:SetBackdropColor(T.panelBg[1], T.panelBg[2], T.panelBg[3], T.panelBg[4])
    frame:SetBackdropBorderColor(T.panelBorder[1], T.panelBorder[2], T.panelBorder[3], T.panelBorder[4])
end

local function CreateShadow(parent)
    local s = CreateFrame("Frame", nil, parent)
    s:SetPoint("TOPLEFT", parent, "TOPLEFT", -4, 4)
    s:SetPoint("BOTTOMRIGHT", parent, "BOTTOMRIGHT", 4, -4)
    s:SetBackdrop({
        bgFile   = "Interface\\Tooltips\\UI-Tooltip-Background",
        edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
        tile = true, tileSize = 16, edgeSize = 16,
        insets = { left = 4, right = 4, top = 4, bottom = 4 },
    })
    s:SetBackdropColor(0, 0, 0, 0.45)
    s:SetBackdropBorderColor(0, 0, 0, 0.6)
    s:SetFrameLevel(math.max(0, parent:GetFrameLevel() - 1))
    return s
end

local function FormatMoney(copper)
    if not copper or copper <= 0 then return 0, 0, 0 end
    local g = math.floor(copper / 10000)
    local s = math.floor(math.mod(copper, 10000) / 100)
    local c = math.mod(copper, 100)
    return g, s, c
end

local function GetBuybackQualityColor(index)
    if not ScanTip then
        ScanTip = CreateFrame("GameTooltip", "SFramesMerchantScanTip", UIParent, "GameTooltipTemplate")
        ScanTip:SetOwner(UIParent, "ANCHOR_NONE")
    end
    ScanTip:ClearLines()
    ScanTip:SetBuybackItem(index)
    local textLine = _G["SFramesMerchantScanTipTextLeft1"]
    if textLine then
        local r, g, b = textLine:GetTextColor()
        if r and g and b then return r, g, b end
    end
    return nil
end

--------------------------------------------------------------------------------
-- Item Stack Helpers
--------------------------------------------------------------------------------
local function GetMaxStack(link)
    if not link then return 1 end
    local _, _, _, _, _, _, ms = GetItemInfo(link)
    if ms and ms > 0 then return ms end
    return 1
end

local function GetItemCountInBags(link)
    if not link then return 0 end
    local _, _, searchID = string.find(link, "item:(%d+)")
    if not searchID then return 0 end
    local total = 0
    for bag = 0, 4 do
        local slots = GetContainerNumSlots(bag)
        for slot = 1, slots do
            local bagLink = GetContainerItemLink(bag, slot)
            if bagLink then
                local _, _, bagID = string.find(bagLink, "item:(%d+)")
                if bagID == searchID then
                    local _, count = GetContainerItemInfo(bag, slot)
                    total = total + (count or 1)
                end
            end
        end
    end
    return total
end

--------------------------------------------------------------------------------
-- Rounded Action Button Factory (for popups)
--------------------------------------------------------------------------------
local function CreateRoundActionBtn(parent, text, w)
    local btn = CreateFrame("Button", nil, parent)
    btn:SetWidth(w or 100)
    btn:SetHeight(28)
    btn:SetBackdrop({
        bgFile   = "Interface\\Tooltips\\UI-Tooltip-Background",
        edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
        tile = true, tileSize = 16, edgeSize = 14,
        insets = { left = 3, right = 3, top = 3, bottom = 3 },
    })
    btn:SetBackdropColor(T.btnBg[1], T.btnBg[2], T.btnBg[3], T.btnBg[4])
    btn:SetBackdropBorderColor(T.btnBorder[1], T.btnBorder[2], T.btnBorder[3], T.btnBorder[4])

    local fs = btn:CreateFontString(nil, "OVERLAY")
    fs:SetFont(GetFont(), 11, "OUTLINE")
    fs:SetPoint("CENTER", 0, 0)
    fs:SetText(text)
    fs:SetTextColor(T.btnText[1], T.btnText[2], T.btnText[3])
    btn.label = fs

    btn.disabled = false
    function btn:SetDisabled(flag)
        self.disabled = flag
        if flag then
            self.label:SetTextColor(T.btnDisabledText[1], T.btnDisabledText[2], T.btnDisabledText[3])
            self:SetBackdropColor(T.btnBg[1], T.btnBg[2], T.btnBg[3], 0.5)
            self:SetBackdropBorderColor(T.slotBorder[1], T.slotBorder[2], T.slotBorder[3], 0.5)
        else
            self.label:SetTextColor(T.btnText[1], T.btnText[2], T.btnText[3])
            self:SetBackdropColor(T.btnBg[1], T.btnBg[2], T.btnBg[3], T.btnBg[4])
            self:SetBackdropBorderColor(T.btnBorder[1], T.btnBorder[2], T.btnBorder[3], T.btnBorder[4])
        end
    end

    btn:SetScript("OnEnter", function()
        if not this.disabled then
            this:SetBackdropColor(T.btnHoverBg[1], T.btnHoverBg[2], T.btnHoverBg[3], T.btnHoverBg[4])
            this:SetBackdropBorderColor(T.btnHoverBd[1], T.btnHoverBd[2], T.btnHoverBd[3], T.btnHoverBd[4])
            this.label:SetTextColor(T.btnActiveText[1], T.btnActiveText[2], T.btnActiveText[3])
        end
    end)
    btn:SetScript("OnLeave", function()
        if not this.disabled then
            this:SetBackdropColor(T.btnBg[1], T.btnBg[2], T.btnBg[3], T.btnBg[4])
            this:SetBackdropBorderColor(T.btnBorder[1], T.btnBorder[2], T.btnBorder[3], T.btnBorder[4])
            this.label:SetTextColor(T.btnText[1], T.btnText[2], T.btnText[3])
        end
    end)
    btn:SetScript("OnMouseDown", function()
        if not this.disabled then
            this:SetBackdropColor(T.btnDownBg[1], T.btnDownBg[2], T.btnDownBg[3], T.btnDownBg[4])
        end
    end)
    btn:SetScript("OnMouseUp", function()
        if not this.disabled then
            this:SetBackdropColor(T.btnHoverBg[1], T.btnHoverBg[2], T.btnHoverBg[3], T.btnHoverBg[4])
        end
    end)

    return btn
end

--------------------------------------------------------------------------------
-- Action Button Factory (matching TrainerUI / QuestUI)
--------------------------------------------------------------------------------
local function CreateActionBtn(parent, text, w)
    local btn = CreateFrame("Button", nil, parent)
    btn:SetWidth(w or 100)
    btn:SetHeight(28)
    btn:SetBackdrop({
        bgFile   = "Interface\\Buttons\\WHITE8X8",
        edgeFile = "Interface\\Buttons\\WHITE8X8",
        tile = false, tileSize = 0, edgeSize = 1,
        insets = { left = 1, right = 1, top = 1, bottom = 1 },
    })
    btn:SetBackdropColor(T.btnBg[1], T.btnBg[2], T.btnBg[3], T.btnBg[4])
    btn:SetBackdropBorderColor(T.btnBorder[1], T.btnBorder[2], T.btnBorder[3], T.btnBorder[4])

    local fs = btn:CreateFontString(nil, "OVERLAY")
    fs:SetFont(GetFont(), 12, "OUTLINE")
    fs:SetPoint("CENTER", 0, 0)
    fs:SetText(text)
    fs:SetTextColor(T.btnText[1], T.btnText[2], T.btnText[3])
    btn.label = fs

    btn.disabled = false
    function btn:SetDisabled(flag)
        self.disabled = flag
        if flag then
            self.label:SetTextColor(T.btnDisabledText[1], T.btnDisabledText[2], T.btnDisabledText[3])
            self:SetBackdropColor(T.btnBg[1], T.btnBg[2], T.btnBg[3], 0.5)
            self:SetBackdropBorderColor(0.2, 0.15, 0.18, 0.5)
        else
            self.label:SetTextColor(T.btnText[1], T.btnText[2], T.btnText[3])
            self:SetBackdropColor(T.btnBg[1], T.btnBg[2], T.btnBg[3], T.btnBg[4])
            self:SetBackdropBorderColor(T.btnBorder[1], T.btnBorder[2], T.btnBorder[3], T.btnBorder[4])
        end
    end

    btn:SetScript("OnEnter", function()
        if not this.disabled then
            this:SetBackdropColor(T.btnHoverBg[1], T.btnHoverBg[2], T.btnHoverBg[3], T.btnHoverBg[4])
            this:SetBackdropBorderColor(T.btnHoverBd[1], T.btnHoverBd[2], T.btnHoverBd[3], T.btnHoverBd[4])
            this.label:SetTextColor(T.btnActiveText[1], T.btnActiveText[2], T.btnActiveText[3])
        end
    end)
    btn:SetScript("OnLeave", function()
        if not this.disabled then
            this:SetBackdropColor(T.btnBg[1], T.btnBg[2], T.btnBg[3], T.btnBg[4])
            this:SetBackdropBorderColor(T.btnBorder[1], T.btnBorder[2], T.btnBorder[3], T.btnBorder[4])
            this.label:SetTextColor(T.btnText[1], T.btnText[2], T.btnText[3])
        end
    end)
    btn:SetScript("OnMouseDown", function()
        if not this.disabled then
            this:SetBackdropColor(T.btnDownBg[1], T.btnDownBg[2], T.btnDownBg[3], T.btnDownBg[4])
        end
    end)
    btn:SetScript("OnMouseUp", function()
        if not this.disabled then
            this:SetBackdropColor(T.btnHoverBg[1], T.btnHoverBg[2], T.btnHoverBg[3], T.btnHoverBg[4])
        end
    end)

    return btn
end

--------------------------------------------------------------------------------
-- Tab Button Factory
--------------------------------------------------------------------------------
local function CreateTabBtn(parent, text, w)
    local btn = CreateFrame("Button", nil, parent)
    btn:SetWidth(w or 70)
    btn:SetHeight(22)
    btn:SetBackdrop({
        bgFile   = "Interface\\Buttons\\WHITE8X8",
        edgeFile = "Interface\\Buttons\\WHITE8X8",
        tile = false, tileSize = 0, edgeSize = 1,
        insets = { left = 1, right = 1, top = 1, bottom = 1 },
    })
    btn:SetBackdropColor(T.tabBg[1], T.tabBg[2], T.tabBg[3], T.tabBg[4])
    btn:SetBackdropBorderColor(T.tabBorder[1], T.tabBorder[2], T.tabBorder[3], 0.5)

    local fs = btn:CreateFontString(nil, "OVERLAY")
    fs:SetFont(GetFont(), 12, "OUTLINE")
    fs:SetPoint("CENTER", 0, 0)
    fs:SetText(text)
    fs:SetTextColor(T.tabText[1], T.tabText[2], T.tabText[3])
    btn.label = fs

    btn:SetScript("OnEnter", function()
        if not this.active then
            this:SetBackdropColor(T.btnHoverBg[1], T.btnHoverBg[2], T.btnHoverBg[3], T.btnHoverBg[4])
            this:SetBackdropBorderColor(T.btnHoverBd[1], T.btnHoverBd[2], T.btnHoverBd[3], T.btnHoverBd[4])
        end
    end)
    btn:SetScript("OnLeave", function()
        if this.active then
            this:SetBackdropColor(T.tabActiveBg[1], T.tabActiveBg[2], T.tabActiveBg[3], T.tabActiveBg[4])
            this:SetBackdropBorderColor(T.tabActiveBorder[1], T.tabActiveBorder[2], T.tabActiveBorder[3], T.tabActiveBorder[4])
        else
            this:SetBackdropColor(T.tabBg[1], T.tabBg[2], T.tabBg[3], T.tabBg[4])
            this:SetBackdropBorderColor(T.tabBorder[1], T.tabBorder[2], T.tabBorder[3], 0.5)
        end
    end)

    function btn:SetActive(flag)
        self.active = flag
        if flag then
            self:SetBackdropColor(T.tabActiveBg[1], T.tabActiveBg[2], T.tabActiveBg[3], T.tabActiveBg[4])
            self:SetBackdropBorderColor(T.tabActiveBorder[1], T.tabActiveBorder[2], T.tabActiveBorder[3], T.tabActiveBorder[4])
            self.label:SetTextColor(T.tabActiveText[1], T.tabActiveText[2], T.tabActiveText[3])
        else
            self:SetBackdropColor(T.tabBg[1], T.tabBg[2], T.tabBg[3], T.tabBg[4])
            self:SetBackdropBorderColor(T.tabBorder[1], T.tabBorder[2], T.tabBorder[3], 0.5)
            self.label:SetTextColor(T.tabText[1], T.tabText[2], T.tabText[3])
        end
    end

    return btn
end

--------------------------------------------------------------------------------
-- Buy Popup (Nanami themed, rounded corners, simple quantity input)
--------------------------------------------------------------------------------
local function EnsureBuyPopup()
    if BuyPopup then return end

    BuyPopup = CreateFrame("Frame", "SFramesMerchantBuyPopup", UIParent)
    BuyPopup:SetWidth(240)
    BuyPopup:SetHeight(110)
    BuyPopup:SetPoint("CENTER", UIParent, "CENTER", 0, 60)
    BuyPopup:SetFrameStrata("DIALOG")
    SetRoundBackdrop(BuyPopup)
    CreateShadow(BuyPopup)
    BuyPopup:Hide()

    local font = GetFont()

    local titleFS = BuyPopup:CreateFontString(nil, "OVERLAY")
    titleFS:SetFont(font, 13, "OUTLINE")
    titleFS:SetPoint("TOP", BuyPopup, "TOP", 0, -12)
    titleFS:SetTextColor(T.gold[1], T.gold[2], T.gold[3])
    titleFS:SetText("批量购买")
    BuyPopup.titleFS = titleFS

    local customLabel = BuyPopup:CreateFontString(nil, "OVERLAY")
    customLabel:SetFont(font, 11, "OUTLINE")
    customLabel:SetPoint("TOP", titleFS, "BOTTOM", -18, -10)
    customLabel:SetTextColor(T.dimText[1], T.dimText[2], T.dimText[3])
    customLabel:SetText("购买数量:")

    local editbox = CreateFrame("EditBox", "SFramesMerchantBuyEditBox", BuyPopup)
    editbox:SetWidth(60)
    editbox:SetHeight(22)
    editbox:SetPoint("LEFT", customLabel, "RIGHT", 6, 0)
    editbox:SetBackdrop({
        bgFile   = "Interface\\Tooltips\\UI-Tooltip-Background",
        edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
        tile = true, tileSize = 16, edgeSize = 12,
        insets = { left = 2, right = 2, top = 2, bottom = 2 },
    })
    editbox:SetBackdropColor(T.inputBg[1], T.inputBg[2], T.inputBg[3], T.inputBg[4] or 0.95)
    editbox:SetBackdropBorderColor(T.slotBorder[1], T.slotBorder[2], T.slotBorder[3], 0.8)
    editbox:SetFont(font, 12, "OUTLINE")
    editbox:SetTextColor(T.nameText[1], T.nameText[2], T.nameText[3])
    editbox:SetJustifyH("CENTER")
    editbox:SetNumeric(true)
    editbox:SetAutoFocus(false)
    editbox:SetTextInsets(4, 4, 2, 2)

    local confirm = CreateRoundActionBtn(BuyPopup, "确定", 75)
    confirm:SetPoint("BOTTOMLEFT", BuyPopup, "BOTTOMLEFT", 28, 12)

    local cancel = CreateRoundActionBtn(BuyPopup, "取消", 75)
    cancel:SetPoint("BOTTOMRIGHT", BuyPopup, "BOTTOMRIGHT", -28, 12)

    BuyPopup.index = 1
    BuyPopup.maxPurchase = 100
    BuyPopup.itemLink = nil

    local function DoBuy()
        local qty = tonumber(editbox:GetText()) or 0
        if qty > 0 then
            if qty > BuyPopup.maxPurchase then qty = BuyPopup.maxPurchase end
            MUI:BuyMultiple(BuyPopup.index, qty)
        end
        BuyPopup:Hide()
    end

    confirm:SetScript("OnClick", DoBuy)
    cancel:SetScript("OnClick", function() BuyPopup:Hide() end)
    editbox:SetScript("OnEnterPressed", DoBuy)
    editbox:SetScript("OnEscapePressed", function() BuyPopup:Hide() end)

    BuyPopup.ShowPopup = function(index, maxAfford, itemLink)
        BuyPopup.index = index
        BuyPopup.maxPurchase = math.min(9999, maxAfford)
        BuyPopup.itemLink = itemLink
        editbox:SetText("1")

        BuyPopup.titleFS:SetText("批量购买")

        BuyPopup:Show()
        editbox:SetFocus()
        editbox:HighlightText()
    end
end

--------------------------------------------------------------------------------
-- Batch Buy Logic
--------------------------------------------------------------------------------
function MUI:BuyMultiple(index, totalAmount)
    if totalAmount <= 0 then return end
    if CurrentTab == 2 then
        BuybackItem(index)
        return
    end

    local name, _, price, batchQty, numAvailable = GetMerchantItemInfo(index)
    local batchSize = (batchQty and batchQty > 0) and batchQty or 1
    local numPurchases = math.ceil(totalAmount / batchSize)

    if numAvailable > -1 and numPurchases > numAvailable then
        numPurchases = numAvailable
    end

    while numPurchases > 0 do
        local batch = numPurchases
        if batch > 255 then batch = 255 end
        BuyMerchantItem(index, batch)
        numPurchases = numPurchases - batch
    end
end

--------------------------------------------------------------------------------
-- Merchant Item Button Factory
--------------------------------------------------------------------------------
local function CreateMerchantButton(parent, id)
    local btn = CreateFrame("Button", "SFramesMerchantItem" .. id, parent)
    btn:SetWidth(ITEM_W)
    btn:SetHeight(ITEM_H)

    local iconFrame = CreateFrame("Button", btn:GetName() .. "Icon", btn)
    iconFrame:SetWidth(ICON_SIZE)
    iconFrame:SetHeight(ICON_SIZE)
    iconFrame:SetPoint("LEFT", btn, "LEFT", 2, 0)
    iconFrame:RegisterForClicks("LeftButtonUp", "RightButtonUp")
    iconFrame:SetBackdrop({
        bgFile   = "Interface\\Tooltips\\UI-Tooltip-Background",
        edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
        tile = true, tileSize = 16, edgeSize = 12,
        insets = { left = 2, right = 2, top = 2, bottom = 2 },
    })
    iconFrame:SetBackdropColor(T.slotBg[1], T.slotBg[2], T.slotBg[3], T.slotBg[4])
    iconFrame:SetBackdropBorderColor(T.slotBorder[1], T.slotBorder[2], T.slotBorder[3], T.slotBorder[4])
    btn.iconFrame = iconFrame

    local qualGlow = iconFrame:CreateTexture(nil, "OVERLAY")
    qualGlow:SetTexture("Interface\\Buttons\\UI-ActionButton-Border")
    qualGlow:SetBlendMode("ADD")
    qualGlow:SetAlpha(0.7)
    qualGlow:SetWidth(ICON_SIZE * 1.8)
    qualGlow:SetHeight(ICON_SIZE * 1.8)
    qualGlow:SetPoint("CENTER", iconFrame, "CENTER", 0, 0)
    qualGlow:Hide()
    btn.qualGlow = qualGlow

    function btn:SetQualityBorder(r, g, b)
        self.qualGlow:SetVertexColor(r, g, b)
        self.qualGlow:Show()
        self.iconFrame:SetBackdropBorderColor(r, g, b, 1)
    end
    function btn:ResetBorder()
        self.qualGlow:Hide()
        self.iconFrame:SetBackdropBorderColor(T.slotBorder[1], T.slotBorder[2], T.slotBorder[3], T.slotBorder[4])
    end

    local icon = iconFrame:CreateTexture(nil, "ARTWORK")
    icon:SetTexCoord(0.08, 0.92, 0.08, 0.92)
    icon:SetPoint("TOPLEFT", iconFrame, "TOPLEFT", 3, -3)
    icon:SetPoint("BOTTOMRIGHT", iconFrame, "BOTTOMRIGHT", -3, 3)
    btn.icon = icon

    local font = GetFont()
    local nameFS = btn:CreateFontString(nil, "OVERLAY")
    nameFS:SetFont(font, 11, "OUTLINE")
    nameFS:SetPoint("TOPLEFT", iconFrame, "TOPRIGHT", 5, -1)
    nameFS:SetPoint("RIGHT", btn, "RIGHT", -2, 0)
    nameFS:SetJustifyH("LEFT")
    nameFS:SetTextColor(T.nameText[1], T.nameText[2], T.nameText[3])
    btn.nameFS = nameFS

    btn.gTxt = btn:CreateFontString(nil, "OVERLAY")
    btn.gTxt:SetFont(font, 10, "OUTLINE")
    btn.gTex = btn:CreateTexture(nil, "ARTWORK")
    btn.gTex:SetTexture("Interface\\MoneyFrame\\UI-MoneyIcons")
    btn.gTex:SetTexCoord(0, 0.25, 0, 1)
    btn.gTex:SetWidth(11); btn.gTex:SetHeight(11)

    btn.sTxt = btn:CreateFontString(nil, "OVERLAY")
    btn.sTxt:SetFont(font, 10, "OUTLINE")
    btn.sTex = btn:CreateTexture(nil, "ARTWORK")
    btn.sTex:SetTexture("Interface\\MoneyFrame\\UI-MoneyIcons")
    btn.sTex:SetTexCoord(0.25, 0.5, 0, 1)
    btn.sTex:SetWidth(11); btn.sTex:SetHeight(11)

    btn.cTxt = btn:CreateFontString(nil, "OVERLAY")
    btn.cTxt:SetFont(font, 10, "OUTLINE")
    btn.cTex = btn:CreateTexture(nil, "ARTWORK")
    btn.cTex:SetTexture("Interface\\MoneyFrame\\UI-MoneyIcons")
    btn.cTex:SetTexCoord(0.5, 0.75, 0, 1)
    btn.cTex:SetWidth(11); btn.cTex:SetHeight(11)

    local countFS = iconFrame:CreateFontString(nil, "OVERLAY")
    countFS:SetFont("Fonts\\ARIALN.TTF", 11, "OUTLINE")
    countFS:SetPoint("BOTTOMRIGHT", iconFrame, "BOTTOMRIGHT", -2, 2)
    countFS:SetJustifyH("RIGHT")
    btn.countFS = countFS

    local highlight = btn:CreateTexture(nil, "HIGHLIGHT")
    highlight:SetTexture("Interface\\QuestFrame\\UI-QuestTitleHighlight")
    highlight:SetBlendMode("ADD")
    highlight:SetAllPoints(btn)
    highlight:SetAlpha(0.15)

    local function OnEnter()
        if not btn.itemIndex then return end
        btn.iconFrame:SetBackdropBorderColor(T.slotHover[1], T.slotHover[2], T.slotHover[3], T.slotHover[4])
        GameTooltip:SetOwner(this, "ANCHOR_RIGHT")
        if CurrentTab == 1 then
            GameTooltip:SetMerchantItem(btn.itemIndex)
            ShowMerchantSellCursor(btn.itemIndex)
            local _, _, price = GetMerchantItemInfo(btn.itemIndex)
            if price and price > 0 then
                GameTooltip:AddLine(" ")
                GameTooltip:AddLine(">> 本店售价:", 1, 0.8, 0)
                SetTooltipMoney(GameTooltip, price)
            end
        else
            GameTooltip:SetBuybackItem(btn.itemIndex)
            local _, _, price = GetBuybackItemInfo(btn.itemIndex)
            if price and price > 0 then
                GameTooltip:AddLine(" ")
                GameTooltip:AddLine(">> 购回需花费:", 1, 0.5, 0)
                SetTooltipMoney(GameTooltip, price)
            end
        end
        local ttLink = (CurrentTab == 1) and GetMerchantItemLink(btn.itemIndex) or nil
        if not ttLink and CurrentTab == 2 and GetBuybackItemLink then
            ttLink = GetBuybackItemLink(btn.itemIndex)
        end
        if ttLink then
            local ms = GetMaxStack(ttLink)
            if ms and ms > 1 then
                GameTooltip:AddLine(" ")
                GameTooltip:AddLine("最大堆叠: " .. ms, 0.5, 0.8, 1)
            end
        end
        if IsControlKeyDown() then ShowInspectCursor() end
        GameTooltip:Show()
    end

    local function OnLeave()
        GameTooltip:Hide()
        ResetCursor()
        if btn._qualR then
            btn.iconFrame:SetBackdropBorderColor(btn._qualR, btn._qualG, btn._qualB, 1)
        else
            btn.iconFrame:SetBackdropBorderColor(T.slotBorder[1], T.slotBorder[2], T.slotBorder[3], T.slotBorder[4])
        end
    end

    iconFrame:SetScript("OnEnter", OnEnter)
    iconFrame:SetScript("OnLeave", OnLeave)

    iconFrame:SetScript("OnUpdate", function()
        if GameTooltip:IsOwned(this) then
            if IsControlKeyDown() then
                if not this.controlDownLast then
                    this.controlDownLast = true
                    ShowInspectCursor()
                end
            else
                if this.controlDownLast then
                    this.controlDownLast = false
                    ResetCursor()
                end
            end
        end
    end)

    iconFrame:SetScript("OnClick", function()
        if not btn.itemIndex then return end
        if IsControlKeyDown() and arg1 == "LeftButton" then
            local link = GetMerchantItemLink(btn.itemIndex)
            if link and DressUpItemLink then
                DressUpItemLink(link)
                return
            end
        end
        if IsShiftKeyDown() then
            if ChatFrameEditBox and ChatFrameEditBox:IsVisible() then
                local link = nil
                if CurrentTab == 1 then link = GetMerchantItemLink(btn.itemIndex) end
                if link then ChatFrameEditBox:Insert(link) end
            else
                if CurrentTab == 1 then
                    local name, _, price, quantity, numAvailable = GetMerchantItemInfo(btn.itemIndex)
                    if not name then return end
                    local popupLink = GetMerchantItemLink(btn.itemIndex)
                    local batchSize = (quantity and quantity > 0) and quantity or 1
                    local maxCanAfford = 9999
                    if price and price > 0 then
                        maxCanAfford = math.floor(GetMoney() / price) * batchSize
                    end
                    if numAvailable > -1 and numAvailable * batchSize < maxCanAfford then
                        maxCanAfford = numAvailable * batchSize
                    end
                    if maxCanAfford < 1 then return end
                    EnsureBuyPopup()
                    BuyPopup.ShowPopup(btn.itemIndex, maxCanAfford, popupLink)
                else
                    BuybackItem(btn.itemIndex)
                end
            end
        elseif arg1 == "RightButton" then
            if CurrentTab == 1 then
                BuyMerchantItem(btn.itemIndex, 1)
            else
                BuybackItem(btn.itemIndex)
            end
        end
    end)

    return btn
end

--------------------------------------------------------------------------------
-- Money Layout Helper
--------------------------------------------------------------------------------
local function LayoutMoney(btn, copper, canBuy)
    btn.gTxt:Hide(); btn.gTex:Hide()
    btn.sTxt:Hide(); btn.sTex:Hide()
    btn.cTxt:Hide(); btn.cTex:Hide()

    local r, g, b
    if canBuy then
        r, g, b = T.bodyText[1], T.bodyText[2], T.bodyText[3]
    else
        r, g, b = T.cantAfford[1], T.cantAfford[2], T.cantAfford[3]
    end

    if copper == 0 then
        btn.cTxt:SetText("0")
        btn.cTxt:SetTextColor(r, g, b)
        btn.cTxt:ClearAllPoints()
        btn.cTxt:SetPoint("BOTTOMLEFT", btn.iconFrame, "BOTTOMRIGHT", 5, 2)
        btn.cTxt:Show()
        btn.cTex:ClearAllPoints()
        btn.cTex:SetPoint("LEFT", btn.cTxt, "RIGHT", 1, 0)
        btn.cTex:Show()
        return
    end

    local vG, vS, vC = FormatMoney(copper)
    local anchor = nil

    local function AttachPair(txt, tex, val, coinR, coinG, coinB)
        txt:SetText(val)
        txt:SetTextColor(canBuy and coinR or r, canBuy and coinG or g, canBuy and coinB or b)
        txt:ClearAllPoints()
        if not anchor then
            txt:SetPoint("BOTTOMLEFT", btn.iconFrame, "BOTTOMRIGHT", 5, 2)
        else
            txt:SetPoint("LEFT", anchor, "RIGHT", 4, 0)
        end
        txt:Show()
        tex:ClearAllPoints()
        tex:SetPoint("LEFT", txt, "RIGHT", 1, 0)
        tex:Show()
        anchor = tex
    end

    if vG > 0 then AttachPair(btn.gTxt, btn.gTex, vG, T.moneyGold[1], T.moneyGold[2], T.moneyGold[3]) end
    if vS > 0 then AttachPair(btn.sTxt, btn.sTex, vS, T.moneySilver[1], T.moneySilver[2], T.moneySilver[3]) end
    if vC > 0 then AttachPair(btn.cTxt, btn.cTex, vC, T.moneyCopper[1], T.moneyCopper[2], T.moneyCopper[3]) end
end

--------------------------------------------------------------------------------
-- Update
--------------------------------------------------------------------------------
function MUI:Update()
    if not MainFrame or not MainFrame:IsVisible() then return end

    local numItems = (CurrentTab == 1) and GetMerchantNumItems() or GetNumBuybackItems()
    local name = UnitName("NPC") or "商人"
    if CurrentTab == 2 then name = name .. " - 购回" end
    MainFrame.npcNameFS:SetText(name)

    local totalPages = math.max(1, math.ceil(numItems / ITEMS_PER_PAGE))
    if CurrentPage > totalPages then CurrentPage = totalPages end
    if CurrentPage < 1 then CurrentPage = 1 end

    MainFrame.pageText:SetText(string.format("第 %d / %d 页", CurrentPage, totalPages))
    MainFrame.prevBtn:SetDisabled(CurrentPage <= 1)
    MainFrame.nextBtn:SetDisabled(CurrentPage >= totalPages)

    MainFrame.tabMerchant:SetActive(CurrentTab == 1)
    MainFrame.tabBuyback:SetActive(CurrentTab == 2)

    for i = 1, ITEMS_PER_PAGE do
        local btn = ItemButtons[i]
        local itemIndex = (CurrentPage - 1) * ITEMS_PER_PAGE + i

        if itemIndex <= numItems then
            local itemName, itemTexture, itemPrice, itemQuantity, numAvailable, isUsable
            local itemLink

            if CurrentTab == 1 then
                itemName, itemTexture, itemPrice, itemQuantity, numAvailable, isUsable = GetMerchantItemInfo(itemIndex)
                itemLink = GetMerchantItemLink(itemIndex)
            else
                itemName, itemTexture, itemPrice, itemQuantity, numAvailable, isUsable = GetBuybackItemInfo(itemIndex)
                if GetBuybackItemLink then itemLink = GetBuybackItemLink(itemIndex) end
            end

            btn.itemIndex = itemIndex
            btn.icon:SetTexture(itemTexture)
            btn.nameFS:SetText(itemName)
            btn._qualR = nil; btn._qualG = nil; btn._qualB = nil

            if CurrentTab == 2 and isUsable == nil then isUsable = true end
            local canAfford = (GetMoney() >= itemPrice)
            local isRequirementBlocked = (CurrentTab == 1 and not isUsable)
            local canBuy = (not isRequirementBlocked) and canAfford
            if canBuy then
                btn.icon:SetVertexColor(1, 1, 1)
                btn.nameFS:SetAlpha(1)
            else
                btn.icon:SetVertexColor(0.5, 0.2, 0.2)
                btn.nameFS:SetAlpha(0.6)
            end

            LayoutMoney(btn, itemPrice, canBuy)

            if CurrentTab == 1 and numAvailable and numAvailable > -1 then
                btn.countFS:SetText(numAvailable)
                if numAvailable == 0 then
                    btn.countFS:SetTextColor(T.dimText[1], T.dimText[2], T.dimText[3])
                else
                    btn.countFS:SetTextColor(T.nameText[1], T.nameText[2], T.nameText[3])
                end
            elseif itemQuantity and itemQuantity > 1 then
                btn.countFS:SetText(itemQuantity)
                btn.countFS:SetTextColor(T.nameText[1], T.nameText[2], T.nameText[3])
            else
                btn.countFS:SetText("")
            end

            local qr, qg, qb
            local quality

            if itemLink then
                local _, _, q = GetItemInfo(itemLink)
                quality = q
                if not quality then
                    local _, _, itemID = string.find(itemLink, "item:(%d+)")
                    if itemID then _, _, quality = GetItemInfo("item:" .. itemID) end
                end
                if quality then
                    qr, qg, qb = GetItemQualityColor(quality)
                else
                    local _, _, hexColor = string.find(itemLink, "|c(%x%x%x%x%x%x%x%x)|")
                    if hexColor then
                        qr = tonumber(string.sub(hexColor, 3, 4), 16) / 255
                        qg = tonumber(string.sub(hexColor, 5, 6), 16) / 255
                        qb = tonumber(string.sub(hexColor, 7, 8), 16) / 255
                    end
                end
            elseif CurrentTab == 2 and itemName then
                qr, qg, qb = GetBuybackQualityColor(itemIndex)
            end

            if isRequirementBlocked then
                -- Level / weapon skill / class requirements not met: always mark red.
                btn.nameFS:SetTextColor(T.unusable[1], T.unusable[2], T.unusable[3])
                btn.nameFS:SetAlpha(1)
                btn.icon:SetVertexColor(0.75, 0.25, 0.25)
                btn:SetQualityBorder(T.unusable[1], T.unusable[2], T.unusable[3])
                btn._qualR = T.unusable[1]; btn._qualG = T.unusable[2]; btn._qualB = T.unusable[3]
            elseif qr then
                btn.nameFS:SetTextColor(qr, qg, qb)
                btn._qualR = qr; btn._qualG = qg; btn._qualB = qb
                if quality and quality > 1 then
                    btn:SetQualityBorder(qr, qg, qb)
                else
                    local isWhite = (qr > 0.95 and qg > 0.95 and qb > 0.95)
                    local isGrey = (qr < 0.7 and qg < 0.7 and qb < 0.7)
                    if not isWhite and not isGrey then
                        btn:SetQualityBorder(qr, qg, qb)
                    else
                        btn:ResetBorder()
                        btn._qualR = nil; btn._qualG = nil; btn._qualB = nil
                    end
                end
            else
                btn.nameFS:SetTextColor(T.nameText[1], T.nameText[2], T.nameText[3])
                btn:ResetBorder()
            end

            if CurrentTab == 1 and numAvailable and numAvailable == 0 then
                btn.icon:SetVertexColor(0.4, 0.4, 0.4)
                btn.nameFS:SetTextColor(T.dimText[1], T.dimText[2], T.dimText[3])
                btn.nameFS:SetAlpha(0.5)
                btn:ResetBorder()
                btn._qualR = nil; btn._qualG = nil; btn._qualB = nil
                LayoutMoney(btn, itemPrice, false)
            end

            btn:Show()
        else
            btn.itemIndex = nil
            btn._qualR = nil; btn._qualG = nil; btn._qualB = nil
            btn:ResetBorder()
            btn:Hide()
        end
    end

    if CanMerchantRepair() then
        MainFrame.repairAllBtn:Show()
        MainFrame.repairItemBtn:Show()
        local repairCost, canRepair = GetRepairAllCost()
        if canRepair and repairCost > 0 and (GetMoney() >= repairCost) then
            MainFrame.repairAllBtn.canClick = true
            if MainFrame.repairAllBtn.iconTex then
                MainFrame.repairAllBtn.iconTex:SetVertexColor(1, 1, 1)
            end
        else
            MainFrame.repairAllBtn.canClick = false
            if MainFrame.repairAllBtn.iconTex then
                MainFrame.repairAllBtn.iconTex:SetVertexColor(0.5, 0.5, 0.5)
            end
        end
    else
        MainFrame.repairAllBtn:Hide()
        MainFrame.repairItemBtn:Hide()
    end
end

--------------------------------------------------------------------------------
-- Initialize
--------------------------------------------------------------------------------
function MUI:Initialize()
    if MainFrame then return end

    MainFrame = CreateFrame("Frame", "SFramesMerchantFrame", UIParent)
    MainFrame:SetWidth(FRAME_W)
    MainFrame:SetHeight(FRAME_H)
    MainFrame:SetPoint("TOPLEFT", UIParent, "TOPLEFT", 12, -104)
    MainFrame:SetFrameStrata("HIGH")
    MainFrame:SetToplevel(true)
    MainFrame:EnableMouse(true)
    MainFrame:SetMovable(true)
    MainFrame:RegisterForDrag("LeftButton")
    MainFrame:SetScript("OnDragStart", function() this:StartMoving() end)
    MainFrame:SetScript("OnDragStop", function() this:StopMovingOrSizing() end)

    SetRoundBackdrop(MainFrame)
    CreateShadow(MainFrame)

    -- Header
    local header = CreateFrame("Frame", nil, MainFrame)
    header:SetPoint("TOPLEFT", MainFrame, "TOPLEFT", 0, 0)
    header:SetPoint("TOPRIGHT", MainFrame, "TOPRIGHT", 0, 0)
    header:SetHeight(HEADER_H)
    header:SetBackdrop({ bgFile = "Interface\\Buttons\\WHITE8X8" })
    header:SetBackdropColor(T.headerBg[1], T.headerBg[2], T.headerBg[3], T.headerBg[4])

    local titleIco = SFrames:CreateIcon(header, "merchant", 16)
    titleIco:SetDrawLayer("OVERLAY")
    titleIco:SetPoint("LEFT", header, "LEFT", SIDE_PAD, 0)
    titleIco:SetVertexColor(T.gold[1], T.gold[2], T.gold[3])

    local npcNameFS = header:CreateFontString(nil, "OVERLAY")
    npcNameFS:SetFont(GetFont(), 14, "OUTLINE")
    npcNameFS:SetPoint("LEFT", titleIco, "RIGHT", 5, 0)
    npcNameFS:SetPoint("RIGHT", header, "RIGHT", -30, 0)
    npcNameFS:SetJustifyH("LEFT")
    npcNameFS:SetTextColor(T.gold[1], T.gold[2], T.gold[3])
    MainFrame.npcNameFS = npcNameFS

    local closeBtn = CreateFrame("Button", nil, header)
    closeBtn:SetWidth(20); closeBtn:SetHeight(20)
    closeBtn:SetPoint("RIGHT", header, "RIGHT", -8, 0)
    local closeTex = closeBtn:CreateTexture(nil, "ARTWORK")
    closeTex:SetTexture("Interface\\AddOns\\Nanami-UI\\img\\icon")
    closeTex:SetTexCoord(0.25, 0.375, 0, 0.125)
    closeTex:SetAllPoints()
    closeTex:SetVertexColor(T.dimText[1], T.dimText[2], T.dimText[3])
    closeBtn:SetScript("OnClick", function() MainFrame:Hide() end)
    closeBtn:SetScript("OnEnter", function() closeTex:SetVertexColor(1, 0.6, 0.7) end)
    closeBtn:SetScript("OnLeave", function() closeTex:SetVertexColor(T.dimText[1], T.dimText[2], T.dimText[3]) end)

    local headerSep = MainFrame:CreateTexture(nil, "ARTWORK")
    headerSep:SetTexture("Interface\\Buttons\\WHITE8X8")
    headerSep:SetHeight(1)
    headerSep:SetPoint("TOPLEFT", MainFrame, "TOPLEFT", 6, -HEADER_H)
    headerSep:SetPoint("TOPRIGHT", MainFrame, "TOPRIGHT", -6, -HEADER_H)
    headerSep:SetVertexColor(T.divider[1], T.divider[2], T.divider[3], T.divider[4])

    -- Tabs
    local tabMerchant = CreateTabBtn(MainFrame, "商人", 60)
    tabMerchant:SetPoint("TOPLEFT", MainFrame, "TOPLEFT", SIDE_PAD, -(HEADER_H + 6))
    tabMerchant:SetScript("OnClick", function()
        CurrentTab = 1
        CurrentPage = 1
        MUI:Update()
    end)
    MainFrame.tabMerchant = tabMerchant

    local tabBuyback = CreateTabBtn(MainFrame, "购回", 60)
    tabBuyback:SetPoint("LEFT", tabMerchant, "RIGHT", 4, 0)
    tabBuyback:SetScript("OnClick", function()
        CurrentTab = 2
        CurrentPage = 1
        MUI:Update()
    end)
    MainFrame.tabBuyback = tabBuyback

    -- Item Grid
    local gridTop = HEADER_H + 6 + 22 + 6
    for i = 1, ITEMS_PER_PAGE do
        local btn = CreateMerchantButton(MainFrame, i)
        local row = math.floor((i - 1) / NUM_COLS)
        local col = math.mod((i - 1), NUM_COLS)
        btn:SetPoint("TOPLEFT", MainFrame, "TOPLEFT",
            SIDE_PAD + col * (ITEM_W + ITEM_GAP_X),
            -(gridTop + row * (ITEM_H + ITEM_GAP_Y)))
        ItemButtons[i] = btn
    end

    -- Bottom bar separator
    local bottomSep = MainFrame:CreateTexture(nil, "ARTWORK")
    bottomSep:SetTexture("Interface\\Buttons\\WHITE8X8")
    bottomSep:SetHeight(1)
    bottomSep:SetPoint("BOTTOMLEFT", MainFrame, "BOTTOMLEFT", 6, BOTTOM_H)
    bottomSep:SetPoint("BOTTOMRIGHT", MainFrame, "BOTTOMRIGHT", -6, BOTTOM_H)
    bottomSep:SetVertexColor(T.divider[1], T.divider[2], T.divider[3], T.divider[4])

    -- Page Navigation
    local prevBtn = CreateActionBtn(MainFrame, "<", 28)
    prevBtn:SetHeight(22)
    prevBtn:SetPoint("BOTTOMLEFT", MainFrame, "BOTTOMLEFT", SIDE_PAD, 14)
    prevBtn:SetScript("OnClick", function()
        CurrentPage = CurrentPage - 1
        MUI:Update()
    end)
    MainFrame.prevBtn = prevBtn

    local nextBtn = CreateActionBtn(MainFrame, ">", 28)
    nextBtn:SetHeight(22)
    nextBtn:SetPoint("LEFT", prevBtn, "RIGHT", 4, 0)
    nextBtn:SetScript("OnClick", function()
        CurrentPage = CurrentPage + 1
        MUI:Update()
    end)
    MainFrame.nextBtn = nextBtn

    local pageText = MainFrame:CreateFontString(nil, "OVERLAY")
    pageText:SetFont(GetFont(), 11, "OUTLINE")
    pageText:SetPoint("LEFT", nextBtn, "RIGHT", 8, 0)
    pageText:SetTextColor(T.dimText[1], T.dimText[2], T.dimText[3])
    MainFrame.pageText = pageText

    -- Repair Buttons
    local repairAllBtn = CreateFrame("Button", nil, MainFrame)
    repairAllBtn:SetWidth(32); repairAllBtn:SetHeight(32)
    repairAllBtn:SetPoint("BOTTOMRIGHT", MainFrame, "BOTTOMRIGHT", -(SIDE_PAD), 10)
    repairAllBtn:SetBackdrop({
        bgFile   = "Interface\\Buttons\\WHITE8X8",
        edgeFile = "Interface\\Buttons\\WHITE8X8",
        tile = false, tileSize = 0, edgeSize = 1,
        insets = { left = 1, right = 1, top = 1, bottom = 1 },
    })
    repairAllBtn:SetBackdropColor(T.btnBg[1], T.btnBg[2], T.btnBg[3], T.btnBg[4])
    repairAllBtn:SetBackdropBorderColor(T.btnBorder[1], T.btnBorder[2], T.btnBorder[3], 0.6)

    local repairAllIcon = repairAllBtn:CreateTexture(nil, "ARTWORK")
    repairAllIcon:SetTexCoord(0.08, 0.92, 0.08, 0.92)
    repairAllIcon:SetPoint("TOPLEFT", 3, -3)
    repairAllIcon:SetPoint("BOTTOMRIGHT", -3, 3)
    repairAllIcon:SetTexture("Interface\\Icons\\Trade_BlackSmithing")
    repairAllBtn.iconTex = repairAllIcon

    repairAllBtn:SetScript("OnClick", function()
        if this.canClick then RepairAllItems() end
    end)
    repairAllBtn:SetScript("OnEnter", function()
        this:SetBackdropColor(T.btnHoverBg[1], T.btnHoverBg[2], T.btnHoverBg[3], T.btnHoverBg[4])
        this:SetBackdropBorderColor(T.btnHoverBd[1], T.btnHoverBd[2], T.btnHoverBd[3], T.btnHoverBd[4])
        GameTooltip:SetOwner(this, "ANCHOR_RIGHT")
        GameTooltip:SetText("修理所有物品", 1, 1, 1)
        local repairCost, canRepair = GetRepairAllCost()
        if canRepair and repairCost > 0 then SetTooltipMoney(GameTooltip, repairCost) end
        GameTooltip:Show()
    end)
    repairAllBtn:SetScript("OnLeave", function()
        this:SetBackdropColor(T.btnBg[1], T.btnBg[2], T.btnBg[3], T.btnBg[4])
        this:SetBackdropBorderColor(T.btnBorder[1], T.btnBorder[2], T.btnBorder[3], 0.6)
        GameTooltip:Hide()
    end)
    MainFrame.repairAllBtn = repairAllBtn

    local repairItemBtn = CreateFrame("Button", nil, MainFrame)
    repairItemBtn:SetWidth(32); repairItemBtn:SetHeight(32)
    repairItemBtn:SetPoint("RIGHT", repairAllBtn, "LEFT", -6, 0)
    repairItemBtn:SetBackdrop({
        bgFile   = "Interface\\Buttons\\WHITE8X8",
        edgeFile = "Interface\\Buttons\\WHITE8X8",
        tile = false, tileSize = 0, edgeSize = 1,
        insets = { left = 1, right = 1, top = 1, bottom = 1 },
    })
    repairItemBtn:SetBackdropColor(T.btnBg[1], T.btnBg[2], T.btnBg[3], T.btnBg[4])
    repairItemBtn:SetBackdropBorderColor(T.btnBorder[1], T.btnBorder[2], T.btnBorder[3], 0.6)

    local repairItemIcon = repairItemBtn:CreateTexture(nil, "ARTWORK")
    repairItemIcon:SetTexCoord(0.08, 0.92, 0.08, 0.92)
    repairItemIcon:SetPoint("TOPLEFT", 3, -3)
    repairItemIcon:SetPoint("BOTTOMRIGHT", -3, 3)
    repairItemIcon:SetTexture("Interface\\Icons\\INV_Hammer_20")
    repairItemBtn.iconTex = repairItemIcon

    repairItemBtn:SetScript("OnClick", function()
        if InRepairMode() then HideRepairCursor() else ShowRepairCursor() end
    end)
    repairItemBtn:SetScript("OnEnter", function()
        this:SetBackdropColor(T.btnHoverBg[1], T.btnHoverBg[2], T.btnHoverBg[3], T.btnHoverBg[4])
        this:SetBackdropBorderColor(T.btnHoverBd[1], T.btnHoverBd[2], T.btnHoverBd[3], T.btnHoverBd[4])
        GameTooltip:SetOwner(this, "ANCHOR_RIGHT")
        GameTooltip:SetText("修理一件物品", 1, 1, 1)
        GameTooltip:Show()
    end)
    repairItemBtn:SetScript("OnLeave", function()
        this:SetBackdropColor(T.btnBg[1], T.btnBg[2], T.btnBg[3], T.btnBg[4])
        this:SetBackdropBorderColor(T.btnBorder[1], T.btnBorder[2], T.btnBorder[3], 0.6)
        GameTooltip:Hide()
    end)
    MainFrame.repairItemBtn = repairItemBtn

    -- Events
    MainFrame:EnableMouseWheel(true)
    MainFrame:SetScript("OnMouseWheel", function()
        local numItems = (CurrentTab == 1) and GetMerchantNumItems() or GetNumBuybackItems()
        local totalPages = math.max(1, math.ceil(numItems / ITEMS_PER_PAGE))
        if arg1 > 0 then
            if CurrentPage > 1 then
                CurrentPage = CurrentPage - 1
                MUI:Update()
            end
        elseif arg1 < 0 then
            if CurrentPage < totalPages then
                CurrentPage = CurrentPage + 1
                MUI:Update()
            end
        end
    end)

    MainFrame:SetScript("OnHide", function() pcall(CloseMerchant) end)
    MainFrame:SetScript("OnEvent", function()
        if event == "MERCHANT_SHOW" then
            if SFramesDB and SFramesDB.enableMerchant == false then return end
            CurrentTab = 1
            CurrentPage = 1
            MainFrame:Show()
            MUI:Update()
        elseif event == "MERCHANT_UPDATE" then
            if MainFrame:IsVisible() then MUI:Update() end
        elseif event == "MERCHANT_CLOSED" then
            MainFrame:Hide()
        end
    end)

    MainFrame:RegisterEvent("MERCHANT_SHOW")
    MainFrame:RegisterEvent("MERCHANT_UPDATE")
    MainFrame:RegisterEvent("MERCHANT_CLOSED")
    MainFrame:Hide()

    if MerchantFrame then
        MerchantFrame:UnregisterEvent("MERCHANT_SHOW")
    end
    tinsert(UISpecialFrames, "SFramesMerchantFrame")
end

--------------------------------------------------------------------------------
-- Bootstrap
--------------------------------------------------------------------------------
local f = CreateFrame("Frame")
f:RegisterEvent("PLAYER_LOGIN")
f:SetScript("OnEvent", function()
    if event == "PLAYER_LOGIN" then
        if SFramesDB and SFramesDB.enableMerchant == nil then
            SFramesDB.enableMerchant = true
        end
        if SFramesDB and SFramesDB.enableMerchant ~= false then
            MUI:Initialize()
        end
    end
end)
