local addonName, BM = ...

local RECIPIENT_PANEL_WIDTH = 324
local ATTACHMENT_COLUMNS = 6
local ATTACHMENT_SIZE = 42
local ATTACHMENT_ICON_FALLBACK = "Interface\\Icons\\INV_Misc_QuestionMark"

local function OpenInventoryBags()
    if ToggleAllBags then
        ToggleAllBags()
        return
    end
    if OpenBackpack then
        OpenBackpack()
    elseif ToggleBackpack then
        ToggleBackpack()
    end
    if OpenBag then
        for bag = 1, 4 do
            OpenBag(bag)
        end
    end
end

local function ParseMoneyField(editBox, maxValue)
    if not editBox then
        return 0
    end

    local value = tonumber(editBox:GetText() or "") or 0
    value = math.floor(math.max(0, value))
    if maxValue then
        value = math.min(maxValue, value)
    end
    return value
end

local function NormalizeCharacterName(name)
    name = strtrim(name or "")
    if name == "" then
        return ""
    end

    if not name:find("-", 1, true) then
        local realm = GetNormalizedRealmName and GetNormalizedRealmName() or nil
        if realm and realm ~= "" then
            return name .. "-" .. realm
        end
    end

    return name
end

local function InsertUniqueRecipient(list, seen, name)
    name = NormalizeCharacterName(name)
    if name == "" or seen[name] then
        return
    end

    seen[name] = true
    table.insert(list, name)
end

function BM:GetRecipientMatches(prefix)
    prefix = (prefix or ""):lower()
    if prefix == "" then
        return {}
    end

    local matches = {}
    local seen = {}
    for _, name in ipairs(BetterMailboxDB.recipientHistory or {}) do
        if not seen[name] and name:lower():find(prefix, 1, true) == 1 then
            seen[name] = true
            table.insert(matches, name)
        end
    end
    return matches
end

function BM:RememberRecipient(name)
    name = NormalizeCharacterName(name)
    if name == "" then
        return
    end

    BetterMailboxDB.recipientHistory = BetterMailboxDB.recipientHistory or {}
    local nextHistory = { name }
    for _, entry in ipairs(BetterMailboxDB.recipientHistory) do
        if entry ~= name and #nextHistory < 15 then
            table.insert(nextHistory, entry)
        end
    end
    BetterMailboxDB.recipientHistory = nextHistory
end

function BM:RefreshRecipientSuggestion()
    if not BM.RecipientSuggestText or not BM.SendRecipientInput then
        return
    end

    local text = BM.SendRecipientInput:GetText() or ""
    local matches = BM:GetRecipientMatches(text)
    if #matches > 0 and text ~= "" and matches[1] ~= text then
        BM.RecipientSuggestText:SetText(BM:L("recent") .. ": " .. matches[1])
        BM.RecipientSuggestText:Show()
        BM.TopRecipientMatch = matches[1]
    else
        BM.RecipientSuggestText:Hide()
        BM.TopRecipientMatch = nil
    end
end

function BM:ApplySendMoney()
    local gold = ParseMoneyField(BM.SendMoneyGoldInput)
    local silver = ParseMoneyField(BM.SendMoneySilverInput, 99)
    local copper = ParseMoneyField(BM.SendMoneyCopperInput, 99)
    local total = (gold * 10000) + (silver * 100) + copper

    if SetSendMailMoney then
        SetSendMailMoney(total)
    end
end

function BM:ResetSendMoney()
    if BM.SendMoneyGoldInput then BM.SendMoneyGoldInput:SetText("") end
    if BM.SendMoneySilverInput then BM.SendMoneySilverInput:SetText("") end
    if BM.SendMoneyCopperInput then BM.SendMoneyCopperInput:SetText("") end
    if SetSendMailMoney then
        SetSendMailMoney(0)
    end
end

function BM:ApplyRecipientSuggestion()
    if BM.TopRecipientMatch and BM.SendRecipientInput then
        BM.SendRecipientInput:SetText(BM.TopRecipientMatch)
        BM.SendRecipientInput:HighlightText(0, 0)
        BM:RefreshRecipientSuggestion()
    end
end

function BM:GetGuildRecipients()
    local recipients = {}
    local seen = {}

    if IsInGuild and IsInGuild() then
        if C_GuildInfo and C_GuildInfo.GuildRoster then
            C_GuildInfo.GuildRoster()
        elseif GuildRoster then
            GuildRoster()
        end

        local total = GetNumGuildMembers and GetNumGuildMembers() or 0
        for i = 1, total do
            local fullName = GetGuildRosterInfo(i)
            InsertUniqueRecipient(recipients, seen, fullName)
        end
    end

    table.sort(recipients)
    return recipients
end

local function GetBattleNetRecipients(recipients, seen)
    if C_BattleNet and C_BattleNet.GetFriendNumGameAccounts and C_BattleNet.GetFriendAccountInfo then
        local total = BNGetNumFriends and BNGetNumFriends() or 0
        for i = 1, total do
            local accountInfo = C_BattleNet.GetFriendAccountInfo(i)
            if accountInfo and accountInfo.gameAccountInfo then
                local gameInfo = accountInfo.gameAccountInfo
                if gameInfo.clientProgram == BNET_CLIENT_WOW and gameInfo.characterName and gameInfo.characterName ~= "" then
                    local fullName = gameInfo.characterName
                    if gameInfo.realmName and gameInfo.realmName ~= "" then
                        fullName = fullName .. "-" .. gameInfo.realmName:gsub("%s+", "")
                    end
                    InsertUniqueRecipient(recipients, seen, fullName)
                end
            end

            local accountGameCount = C_BattleNet.GetFriendNumGameAccounts(i) or 0
            for gameIndex = 1, accountGameCount do
                local gameInfo = C_BattleNet.GetFriendGameAccountInfo(i, gameIndex)
                if gameInfo and gameInfo.clientProgram == BNET_CLIENT_WOW and gameInfo.characterName and gameInfo.characterName ~= "" then
                    local fullName = gameInfo.characterName
                    if gameInfo.realmName and gameInfo.realmName ~= "" then
                        fullName = fullName .. "-" .. gameInfo.realmName:gsub("%s+", "")
                    end
                    InsertUniqueRecipient(recipients, seen, fullName)
                end
            end
        end
        return
    end

    if BNGetNumFriends and BNGetFriendInfo and BNGetNumFriendGameAccounts and BNGetFriendGameAccountInfo then
        local total = BNGetNumFriends()
        for i = 1, total do
            local gameCount = BNGetNumFriendGameAccounts(i) or 0
            for gameIndex = 1, gameCount do
                local _, characterName, _, realmName, _, clientProgram = BNGetFriendGameAccountInfo(i, gameIndex)
                if clientProgram == BNET_CLIENT_WOW and characterName and characterName ~= "" then
                    local fullName = characterName
                    if realmName and realmName ~= "" then
                        fullName = fullName .. "-" .. realmName:gsub("%s+", "")
                    end
                    InsertUniqueRecipient(recipients, seen, fullName)
                end
            end
        end
    end
end

function BM:GetFriendRecipients()
    local recipients = {}
    local seen = {}

    if C_FriendList and C_FriendList.GetNumFriends then
        if C_FriendList.ShowFriends then
            C_FriendList.ShowFriends()
        end
        local total = C_FriendList.GetNumFriends()
        for i = 1, total do
            local info = C_FriendList.GetFriendInfoByIndex(i)
            if info and info.name then
                InsertUniqueRecipient(recipients, seen, info.name)
            end
        end
    elseif GetNumFriends and GetFriendInfo then
        local total = GetNumFriends()
        for i = 1, total do
            local name = GetFriendInfo(i)
            InsertUniqueRecipient(recipients, seen, name)
        end
    end

    GetBattleNetRecipients(recipients, seen)

    table.sort(recipients)
    return recipients
end

function BM:SetRecipientBrowserMode(mode)
    if not BM.RecipientBrowser then
        return
    end

    if mode ~= "guild" and mode ~= "friends" then
        mode = nil
    end

    BM.RecipientPopupMode = mode

    if not mode then
        BM.RecipientBrowser:Hide()
        if BM.ComposeFrame then
            BM.ComposeFrame:ClearAllPoints()
            BM.ComposeFrame:SetPoint("TOPLEFT", 20, -18)
            BM.ComposeFrame:SetPoint("TOPRIGHT", -20, -18)
            BM.ComposeFrame:SetPoint("BOTTOMRIGHT", -20, 20)
        end
        return
    end

    BM.RecipientPopupList = mode == "guild" and BM:GetGuildRecipients() or BM:GetFriendRecipients()
    BM.RecipientBrowser:Show()

    if BM.ComposeFrame then
        BM.ComposeFrame:ClearAllPoints()
        BM.ComposeFrame:SetPoint("TOPLEFT", 20, -18)
        BM.ComposeFrame:SetPoint("TOPRIGHT", BM.RecipientBrowser, "TOPLEFT", -16, 0)
        BM.ComposeFrame:SetPoint("BOTTOMRIGHT", BM.RecipientBrowser, "BOTTOMLEFT", -16, 0)
    end

    if BM.RecipientBrowserTitle then
        BM.RecipientBrowserTitle:SetText(mode == "guild" and BM:L("guild") or BM:L("friends"))
    end

    if BM.RecipientBrowserSearch then
        BM.RecipientBrowserSearch:SetText("")
    end

    BM:RefreshRecipientPopupList("")
end

function BM:OpenRecipientPopup(mode)
    if BM.RecipientPopupMode == mode and BM.RecipientBrowser and BM.RecipientBrowser:IsShown() then
        BM:SetRecipientBrowserMode(nil)
    else
        BM:SetRecipientBrowserMode(mode)
    end
end

function BM:RefreshRecipientPopupList(query)
    if not BM.RecipientPopupButtons then
        return
    end

    query = (query or ""):lower()
    local filtered = {}
    for _, name in ipairs(BM.RecipientPopupList or {}) do
        if query == "" or name:lower():find(query, 1, true) then
            table.insert(filtered, name)
        end
    end

    local anchor
    for i, button in ipairs(BM.RecipientPopupButtons) do
        local name = filtered[i]
        button:ClearAllPoints()
        if name then
            button.recipientName = name
            button.label:SetText(name)
            if not anchor then
                button:SetPoint("TOPLEFT", 0, 0)
            else
                button:SetPoint("TOPLEFT", anchor, "BOTTOMLEFT", 0, -6)
            end
            anchor = button
            button:Show()
        else
            button.recipientName = nil
            button:Hide()
        end
    end

    local buttonHeight = 34
    local spacing = 6
    local viewportHeight = BM.RecipientPopupScrollFrame and (BM.RecipientPopupScrollFrame:GetHeight() or 0) or 0
    local rawHeight = math.max(24, (#filtered * (buttonHeight + spacing)) - spacing)
    local contentHeight = math.max(rawHeight, viewportHeight)
    if BM.RecipientPopupScrollChild then
        BM.RecipientPopupScrollChild:SetHeight(contentHeight)
    end

    if BM.RecipientPopupEmpty then
        BM.RecipientPopupEmpty:SetShown(#filtered == 0)
    end

    if BM.RecipientPopupScrollFrame then
        BM.RecipientPopupScrollFrame:UpdateScrollChildRect()
        BM.RecipientPopupScrollFrame:SetVerticalScroll(0)

        local maxScroll = math.max(0, rawHeight - viewportHeight)
        local canScroll = maxScroll > 0
        local scrollBar = BM.RecipientPopupScrollFrame.ScrollBar
        if scrollBar then
            scrollBar:SetMinMaxValues(0, maxScroll)
            scrollBar:SetValue(0)
            scrollBar:SetShown(canScroll)
        end
    end
end

function BM:CreateSendUI()
    local panel = BM.SendPanel

    local hero = BM:CreatePanel(panel)
    hero:SetPoint("TOPLEFT", 16, -16)
    hero:SetPoint("TOPRIGHT", -16, -16)
    hero:SetHeight(88)
    hero:SetBackdropColor(0.05, 0.065, 0.095, 0.985)

    local heroTitle = hero:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    heroTitle:SetPoint("TOPLEFT", 18, -14)
    heroTitle:SetTextColor(unpack(BM.Theme.text))

    local heroSub = hero:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    heroSub:SetPoint("TOPLEFT", heroTitle, "BOTTOMLEFT", 0, -8)
    heroSub:SetTextColor(unpack(BM.Theme.mutetext))

    local friendsButton = BM:CreateFlatActionButton(hero, 116, 30, "")
    friendsButton:SetPoint("RIGHT", -16, 0)
    friendsButton:SetScript("OnClick", function()
        BM:OpenRecipientPopup("friends")
    end)

    local guildButton = BM:CreateFlatActionButton(hero, 116, 30, "")
    guildButton:SetPoint("RIGHT", friendsButton, "LEFT", -10, 0)
    guildButton:SetScript("OnClick", function()
        BM:OpenRecipientPopup("guild")
    end)

    local form = BM:CreatePanel(panel)
    form:SetPoint("TOPLEFT", 16, -120)
    form:SetPoint("BOTTOMRIGHT", -16, 16)
    form:SetBackdropColor(0.035, 0.045, 0.065, 0.985)

    local compose = CreateFrame("Frame", nil, form)
    compose:SetPoint("TOPLEFT", 20, -18)
    compose:SetPoint("TOPRIGHT", -20, -18)
    compose:SetPoint("BOTTOMRIGHT", -20, 20)

    local recipientLabel = compose:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
    recipientLabel:SetPoint("TOPLEFT", 0, 0)
    recipientLabel:SetTextColor(unpack(BM.Theme.mutetext))

    local recipientInput = BM:CreateInput(compose, 120, 40, false)
    recipientInput:SetPoint("TOPLEFT", 0, -22)
    recipientInput:SetPoint("RIGHT", compose, "CENTER", -8, -22)
    recipientInput.EditBox:SetScript("OnTextChanged", function()
        BM:RefreshRecipientSuggestion()
    end)
    recipientInput.EditBox:SetScript("OnTabPressed", function(self)
        BM:ApplyRecipientSuggestion()
        self:ClearFocus()
    end)

    local subjectLabel = compose:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
    subjectLabel:SetPoint("TOPLEFT", compose, "TOP", 8, 0)
    subjectLabel:SetTextColor(unpack(BM.Theme.mutetext))

    local subjectInput = BM:CreateInput(compose, 120, 40, false)
    subjectInput:SetPoint("TOPLEFT", compose, "TOP", 8, -22)
    subjectInput:SetPoint("RIGHT", compose, "RIGHT", 0, 0)

    local recipientSuggest = compose:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    recipientSuggest:SetPoint("TOPLEFT", recipientInput, "BOTTOMLEFT", 2, -6)
    recipientSuggest:SetTextColor(unpack(BM.Theme.accent))
    recipientSuggest:Hide()

    local bodyLabel = compose:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
    bodyLabel:SetPoint("TOPLEFT", 0, -86)
    bodyLabel:SetTextColor(unpack(BM.Theme.mutetext))

    local bodyInput = BM:CreateInput(compose, 300, 260, true)
    bodyInput:SetPoint("TOPLEFT", 0, -108)
    bodyInput:SetPoint("RIGHT", compose, "RIGHT", 0, 0)

    local attachmentsLabel = compose:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
    attachmentsLabel:SetPoint("BOTTOMLEFT", 0, 118)
    attachmentsLabel:SetTextColor(unpack(BM.Theme.mutetext))

    local attachmentPanel = BM:CreatePanel(compose)
    attachmentPanel:SetPoint("BOTTOMLEFT", 0, 0)
    attachmentPanel:SetPoint("RIGHT", compose, "RIGHT", 0, 0)
    attachmentPanel:SetHeight(118)
    attachmentPanel:SetBackdropColor(0.03, 0.04, 0.06, 1)

    local slotAnchor = CreateFrame("Frame", nil, attachmentPanel)
    slotAnchor:SetPoint("LEFT", 14, 0)
    slotAnchor:SetSize(ATTACHMENT_COLUMNS * (ATTACHMENT_SIZE + 8), 92)

    local hint = compose:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    hint:SetPoint("BOTTOMLEFT", attachmentPanel, "BOTTOMLEFT", 14, 12)
    hint:SetTextColor(unpack(BM.Theme.mutetext))

    local actionBlock = CreateFrame("Frame", nil, attachmentPanel)
    actionBlock:SetPoint("LEFT", slotAnchor, "RIGHT", 24, 0)
    actionBlock:SetPoint("RIGHT", attachmentPanel, "RIGHT", -18, 0)
    actionBlock:SetHeight(78)

    local moneyBlock = CreateFrame("Frame", nil, actionBlock)
    moneyBlock:SetPoint("TOPLEFT", 0, -4)
    moneyBlock:SetWidth(250)
    moneyBlock:SetHeight(56)

    local moneyLabel = moneyBlock:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
    moneyLabel:SetPoint("TOPLEFT", 0, 0)
    moneyLabel:SetTextColor(unpack(BM.Theme.mutetext))
    moneyLabel:SetJustifyH("LEFT")

    local moneyRow = CreateFrame("Frame", nil, moneyBlock)
    moneyRow:SetPoint("TOPLEFT", moneyLabel, "BOTTOMLEFT", 0, -22)
    moneyRow:SetPoint("TOPRIGHT", moneyBlock, "TOPRIGHT", 0, -10)
    moneyRow:SetHeight(28)

    local goldIcon = moneyRow:CreateTexture(nil, "ARTWORK")
    goldIcon:SetTexture("Interface\\MoneyFrame\\UI-GoldIcon")
    goldIcon:SetSize(14, 14)
    goldIcon:SetPoint("LEFT", 0, 0)

    local moneyGoldInput = BM:CreateInput(moneyRow, 50, 28, false)
    moneyGoldInput:SetPoint("LEFT", goldIcon, "RIGHT", 6, 0)
    moneyGoldInput.EditBox:SetNumeric(true)
    moneyGoldInput.EditBox:SetMaxLetters(6)
    moneyGoldInput.EditBox:SetScript("OnTextChanged", function()
        BM:ApplySendMoney()
    end)

    local silverIcon = moneyRow:CreateTexture(nil, "ARTWORK")
    silverIcon:SetTexture("Interface\\MoneyFrame\\UI-SilverIcon")
    silverIcon:SetSize(14, 14)
    silverIcon:SetPoint("LEFT", moneyGoldInput, "RIGHT", 14, 0)

    local moneySilverInput = BM:CreateInput(moneyRow, 34, 28, false)
    moneySilverInput:SetPoint("LEFT", silverIcon, "RIGHT", 6, 0)
    moneySilverInput.EditBox:SetNumeric(true)
    moneySilverInput.EditBox:SetMaxLetters(2)
    moneySilverInput.EditBox:SetScript("OnTextChanged", function()
        BM:ApplySendMoney()
    end)

    local copperIcon = moneyRow:CreateTexture(nil, "ARTWORK")
    copperIcon:SetTexture("Interface\\MoneyFrame\\UI-CopperIcon")
    copperIcon:SetSize(14, 14)
    copperIcon:SetPoint("LEFT", moneySilverInput, "RIGHT", 14, 0)

    local moneyCopperInput = BM:CreateInput(moneyRow, 34, 28, false)
    moneyCopperInput:SetPoint("LEFT", copperIcon, "RIGHT", 6, 0)
    moneyCopperInput.EditBox:SetNumeric(true)
    moneyCopperInput.EditBox:SetMaxLetters(2)
    moneyCopperInput.EditBox:SetScript("OnTextChanged", function()
        BM:ApplySendMoney()
    end)

    local sendButton = BM:CreateFlatActionButton(actionBlock, 172, 34, "")
    sendButton:SetPoint("RIGHT", actionBlock, "RIGHT", 0, 0)
    sendButton:SetScript("OnClick", function()
        BM:SendCurrentMail()
    end)

    bodyInput:SetPoint("BOTTOM", attachmentsLabel, "TOP", 0, 14)

    local browser = BM:CreatePanel(form)
    browser:SetPoint("TOPRIGHT", -20, -18)
    browser:SetPoint("BOTTOMRIGHT", -20, 20)
    browser:SetWidth(RECIPIENT_PANEL_WIDTH)
    browser:SetBackdropColor(0.042, 0.052, 0.076, 0.99)
    browser:Hide()

    local browserTitle = browser:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    browserTitle:SetPoint("TOPLEFT", 16, -14)
    browserTitle:SetTextColor(unpack(BM.Theme.text))

    local browserClose = BM:CreateFlatActionButton(browser, 28, 24, "X")
    browserClose:SetPoint("TOPRIGHT", -12, -10)
    browserClose:SetScript("OnClick", function()
        BM:SetRecipientBrowserMode(nil)
    end)

    local browserSearch = BM:CreateInput(browser, RECIPIENT_PANEL_WIDTH - 32, 34, false)
    browserSearch:SetPoint("TOPLEFT", 16, -42)
    browserSearch.EditBox:SetScript("OnTextChanged", function(self)
        BM:RefreshRecipientPopupList(self:GetText() or "")
    end)

    local scrollFrame = CreateFrame("ScrollFrame", nil, browser, "UIPanelScrollFrameTemplate")
    scrollFrame:SetPoint("TOPLEFT", 16, -86)
    scrollFrame:SetPoint("BOTTOMRIGHT", -28, 16)

    local scrollChild = CreateFrame("Frame", nil, scrollFrame)
    scrollChild:SetSize(RECIPIENT_PANEL_WIDTH - 52, 1)
    scrollFrame:SetScrollChild(scrollChild)

    local empty = scrollChild:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    empty:SetPoint("TOPLEFT", 8, -8)
    empty:SetTextColor(unpack(BM.Theme.mutetext))
    empty:SetWidth(RECIPIENT_PANEL_WIDTH - 70)
    empty:SetJustifyH("LEFT")
    empty:SetText("")
    empty:Hide()

    local popupButtons = {}
    for i = 1, 20 do
        local button = BM:CreateFlatActionButton(scrollChild, RECIPIENT_PANEL_WIDTH - 52, 34, "")
        button:SetScript("OnClick", function(self)
            if BM.SendRecipientInput and self.recipientName then
                BM.SendRecipientInput:SetText(self.recipientName)
                BM:SetRecipientBrowserMode(nil)
                BM:RefreshRecipientSuggestion()
            end
        end)
        popupButtons[i] = button
    end

    BM.SendHeroTitle = heroTitle
    BM.SendHeroSubtitle = heroSub
    BM.SendGuildButton = guildButton
    BM.SendFriendsButton = friendsButton
    BM.ComposeFrame = compose
    BM.SendRecipientInput = recipientInput.EditBox
    BM.SendSubjectInput = subjectInput.EditBox
    BM.SendBodyInput = bodyInput.EditBox
    BM.SendMailButton = sendButton
    BM.SendRecipientLabel = recipientLabel
    BM.SendSubjectLabel = subjectLabel
    BM.SendBodyLabel = bodyLabel
    BM.SendAttachmentsLabel = attachmentsLabel
    BM.SendHintText = hint
    BM.SendMoneyBlock = moneyBlock
    BM.SendMoneyLabel = moneyLabel
    BM.SendMoneyRow = moneyRow
    BM.SendMoneyGoldIcon = goldIcon
    BM.SendMoneySilverIcon = silverIcon
    BM.SendMoneyCopperIcon = copperIcon
    BM.SendMoneyGoldInput = moneyGoldInput.EditBox
    BM.SendMoneySilverInput = moneySilverInput.EditBox
    BM.SendMoneyCopperInput = moneyCopperInput.EditBox
    BM.RecipientSuggestText = recipientSuggest
    BM.SendAttachmentPanel = attachmentPanel
    BM.SendAttachmentAnchor = slotAnchor
    BM.RecipientBrowser = browser
    BM.RecipientBrowserTitle = browserTitle
    BM.RecipientBrowserSearch = browserSearch.EditBox
    BM.RecipientBrowserClose = browserClose
    BM.RecipientPopup = browser
    BM.RecipientPopupTitle = browserTitle
    BM.RecipientPopupSearch = browserSearch.EditBox
    BM.RecipientPopupButtons = popupButtons
    BM.RecipientPopupScrollFrame = scrollFrame
    BM.RecipientPopupScrollChild = scrollChild
    BM.RecipientPopupEmpty = empty
    BM:UpdateSendTexts()
end

function BM:UpdateSendTexts()
    if BM.SendHeroTitle then BM.SendHeroTitle:SetText(BM:L("send")) end
    if BM.SendHeroSubtitle then BM.SendHeroSubtitle:SetText(BM:L("compose_status")) end
    if BM.SendGuildButton and BM.SendGuildButton.label then BM.SendGuildButton.label:SetText(BM:L("guild")) end
    if BM.SendFriendsButton and BM.SendFriendsButton.label then BM.SendFriendsButton.label:SetText(BM:L("friends")) end
    if BM.SendRecipientLabel then BM.SendRecipientLabel:SetText(BM:L("recipient")) end
    if BM.SendSubjectLabel then BM.SendSubjectLabel:SetText(BM:L("subject")) end
    if BM.SendBodyLabel then BM.SendBodyLabel:SetText(BM:L("message")) end
    if BM.SendAttachmentsLabel then BM.SendAttachmentsLabel:SetText(BM:L("attachments")) end
    if BM.SendHintText then BM.SendHintText:SetText(BM:L("send_hint")) end
    if BM.SendMoneyLabel then BM.SendMoneyLabel:SetText(string.upper(BM:L("send_gold"))) end
    if BM.SendMailButton and BM.SendMailButton.label then BM.SendMailButton.label:SetText(BM:L("send_mail")) end
    if BM.RecipientBrowserTitle then
        local mode = BM.RecipientPopupMode == "guild" and BM:L("guild") or BM:L("friends")
        BM.RecipientBrowserTitle:SetText(BM.RecipientPopupMode and mode or "")
    end
    if BM.RecipientPopupEmpty then
        BM.RecipientPopupEmpty:SetText(BM:L("no_results"))
    end
end

function BM:RefreshAttachmentSlots()
    if not BM.SendAttachmentSlots then
        return
    end

    local maxSlots = ATTACHMENTS_MAX_SEND or 12
    for i = 1, maxSlots do
        local slot = BM.SendAttachmentSlots[i]
        if slot then
            local name, itemID, texture, count, quality = nil, nil, nil, nil, nil
            if GetSendMailItem then
                name, itemID, texture, count, quality = GetSendMailItem(i)
            end

            if texture then
                slot.icon:SetTexture(texture)
                slot.icon:Show()
                slot.icon:SetDesaturated(false)
                slot.icon:SetVertexColor(1, 1, 1, 1)
                if slot.count then
                    slot.count:SetText(count and count > 1 and count or "")
                end
                if quality and quality > 1 and slot.SetBackdropBorderColor then
                    local color = ITEM_QUALITY_COLORS and ITEM_QUALITY_COLORS[quality]
                    if color then
                        slot:SetBackdropBorderColor(color.r, color.g, color.b, 1)
                    end
                else
                    slot:SetBackdropBorderColor(0.12, 0.16, 0.23, 1)
                end
            else
                slot.icon:SetTexture(ATTACHMENT_ICON_FALLBACK)
                slot.icon:SetDesaturated(true)
                slot.icon:SetVertexColor(0.35, 0.42, 0.52, 1)
                slot.icon:Show()
                if slot.count then
                    slot.count:SetText("")
                end
                slot:SetBackdropBorderColor(0.12, 0.16, 0.23, 1)
            end
        end
    end
end

function BM:EmbedSendAttachmentSlots()
    if not BM.SendAttachmentAnchor then
        return
    end

    BM.SendAttachmentSlots = BM.SendAttachmentSlots or {}
    local maxSlots = ATTACHMENTS_MAX_SEND or 12

    for i = 1, maxSlots do
        local slot = BM.SendAttachmentSlots[i]

        if not slot then
            slot = CreateFrame("Button", nil, BM.SendAttachmentAnchor, "BackdropTemplate")
            slot:SetSize(ATTACHMENT_SIZE, ATTACHMENT_SIZE)
            slot:SetBackdrop({
                bgFile = "Interface/Buttons/WHITE8X8",
                edgeFile = "Interface/Buttons/WHITE8X8",
                edgeSize = 1,
            })
            slot:SetBackdropColor(0.03, 0.04, 0.06, 1)
            slot:SetBackdropBorderColor(0.12, 0.16, 0.23, 1)

            local row = math.floor((i - 1) / ATTACHMENT_COLUMNS)
            local col = (i - 1) % ATTACHMENT_COLUMNS
            slot:SetPoint("TOPLEFT", col * (ATTACHMENT_SIZE + 8), -row * (ATTACHMENT_SIZE + 8))

            local icon = slot:CreateTexture(nil, "ARTWORK")
            icon:SetPoint("TOPLEFT", 5, -5)
            icon:SetPoint("BOTTOMRIGHT", -5, 5)
            icon:SetTexture(ATTACHMENT_ICON_FALLBACK)
            icon:SetDesaturated(true)
            icon:SetVertexColor(0.35, 0.42, 0.52, 1)
            slot.icon = icon

            local count = slot:CreateFontString(nil, "OVERLAY", "NumberFontNormalSmall")
            count:SetPoint("BOTTOMRIGHT", -4, 4)
            count:SetTextColor(1, 1, 1, 1)
            slot.count = count

            slot.slotIndex = i
            slot:RegisterForClicks("LeftButtonUp", "RightButtonUp")
            slot:RegisterForDrag("LeftButton")
            slot:SetScript("OnReceiveDrag", function(self)
                if CursorHasItem and CursorHasItem() and ClickSendMailItemButton then
                    ClickSendMailItemButton(self.slotIndex)
                    ClearCursor()
                    BM:RefreshAttachmentSlots()
                end
            end)
            slot:SetScript("OnMouseUp", function(self, button)
                if button == "RightButton" then
                    if ClickSendMailItemButton then
                        ClickSendMailItemButton(self.slotIndex, true)
                        BM:RefreshAttachmentSlots()
                    end
                elseif CursorHasItem and CursorHasItem() and ClickSendMailItemButton then
                    ClickSendMailItemButton(self.slotIndex)
                    ClearCursor()
                    BM:RefreshAttachmentSlots()
                else
                    local hasAttachment = GetSendMailItem and GetSendMailItem(self.slotIndex)
                    if not hasAttachment then
                        OpenInventoryBags()
                    end
                end
            end)
            slot:SetScript("OnEnter", function(self)
                if GetSendMailItem and GameTooltip then
                    local name = GetSendMailItem(self.slotIndex)
                    if name then
                        GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
                        GameTooltip:SetSendMailItem(self.slotIndex)
                        GameTooltip:Show()
                    end
                end
            end)
            slot:SetScript("OnLeave", function()
                GameTooltip_Hide()
            end)

            BM.SendAttachmentSlots[i] = slot
        end

        slot:Show()
    end

    BM:RefreshAttachmentSlots()
end

function BM:SendCurrentMail()
    local recipient = BM.SendRecipientInput and BM.SendRecipientInput:GetText() or ""
    local subject = BM.SendSubjectInput and BM.SendSubjectInput:GetText() or ""
    local body = BM.SendBodyInput and BM.SendBodyInput:GetText() or ""

    recipient = NormalizeCharacterName(recipient)
    if recipient == "" then
        BM:SetStatus(BM:L("recipient_required"), 1, 0.35, 0.35)
        return
    end

    if subject == "" then
        subject = " "
    end

    BM:ApplySendMoney()
    SendMail(recipient, subject, body)
    BM:SetStatus(BM:L("sending_status"), 0.13, 0.72, 1)

    if BM.SendMailButton and BM.SendMailButton.label then
        BM.SendMailButton:Disable()
        BM.SendMailButton.label:SetText(BM:L("sending"))
    end
end

function BM:HandleSendSuccess()
    BM:RememberRecipient(BM.SendRecipientInput and BM.SendRecipientInput:GetText() or "")
    if BM.SendRecipientInput then BM.SendRecipientInput:SetText("") end
    if BM.SendSubjectInput then BM.SendSubjectInput:SetText("") end
    if BM.SendBodyInput then BM.SendBodyInput:SetText("") end
    BM:ResetSendMoney()

    if BM.SendMailButton and BM.SendMailButton.label then
        BM.SendMailButton:Enable()
        BM.SendMailButton.label:SetText(BM:L("send_mail"))
    end

    BM:SetStatus(BM:L("sent_success"), unpack(BM.Theme.success))
end

function BM:HandleSendFailure()
    if BM.SendMailButton and BM.SendMailButton.label then
        BM.SendMailButton:Enable()
        BM.SendMailButton.label:SetText(BM:L("send_mail"))
    end

    BM:SetStatus(BM:L("sent_fail"), unpack(BM.Theme.danger))
end

function BM:PrepareReply(recipient, subject)
    recipient = NormalizeCharacterName(recipient or "")
    subject = strtrim(subject or "")

    if recipient == "" then
        BM:SetStatus(BM:L("recipient_required"), unpack(BM.Theme.danger))
        return
    end

    if subject == "" then
        subject = BM:L("no_subject")
    end

    if not subject:lower():find("^re:%s*", 1) then
        subject = "Re: " .. subject
    end

    BM.openMailIndex = nil
    BM:SelectTab("send")

    if BM.SendRecipientInput then
        BM.SendRecipientInput:SetText(recipient)
        BM.SendRecipientInput:HighlightText(0, 0)
    end
    if BM.SendSubjectInput then
        BM.SendSubjectInput:SetText(subject)
        BM.SendSubjectInput:HighlightText(0, 0)
    end
    if BM.SendBodyInput then
        BM.SendBodyInput:SetText("")
    end
    BM:ResetSendMoney()

    BM:RefreshRecipientSuggestion()
    BM:SetStatus(BM:L("reply_prepared"), 0.2, 0.72, 1)
end
