local PT = AhUI
if not PT then return end

PT.GoldDepositor = PT.GoldDepositor or {}
local GD = PT.GoldDepositor

local Tooltip = PT.Tooltip
local FONT = PT.FONT or "Interface\\AddOns\\AhUI\\fonts\\GothamXNarrow-Medium.ttf"
local L = PT.L or {}

local function T(key, default)
    return L[key] or default or key
end

local function IsModuleEnabled()
    return not (PT.config and PT.config.goldDepositorEnabled == false)
end


local ADDON_NAME = ... or "AhUI"

local DEFAULT_KEEP = 200
local BUTTON_SIZE = 64
local DEFAULT_POINT = "CENTER"
local DEFAULT_X = 0
local DEFAULT_Y = 0
local POSITION_VERSION = 1
local ACCOUNT_BANK_SIGNAL_GRACE = 2.0

local BANK_TYPE_GUILD = "guild"
local BANK_TYPE_ACCOUNT = "account"

local PREFIX = "|cff00ccff[AhUI Gold Depositor]|r"
local ERROR_PREFIX = "|cffff4444[AhUI Gold Depositor]|r"
local OK_PREFIX = "|cff00ff00[AhUI Gold Depositor]|r"

local KEY_COLOR = "|cffffd200"
local ON_COLOR = "|cff00ff00"
local OFF_COLOR = "|cffff4444"
local INFO_COLOR = "|cff00ccff"
local TEXT_COLOR = "|cffffffff"
local DIM_COLOR = "|cffaaaaaa"
local RESET_COLOR = "|r"

local button
local keepPopup
local depositInProgress = false
local autoDepositQueued = false
local autoDepositToken = 0
local bankSessionOpen = false
local currentBankType = nil
local lastBankSignalAt = 0
local accountBankHooksInstalled = false

local function Now()
    if GetTime then
        return GetTime()
    end

    return 0
end

local function Trim(value)
    value = value or ""

    if strtrim then
        return strtrim(value)
    end

    return tostring(value):match("^%s*(.-)%s*$") or ""
end

local function EnsureDB()
    AhUI_DB = AhUI_DB or {}
    AhUI_DB.goldDepositor = AhUI_DB.goldDepositor or {}

    local db = AhUI_DB.goldDepositor

    if not db._migratedStandalone then
        local legacy = rawget(_G, "GoldDepositorDB")

        if type(legacy) == "table" then
            if db.keepGold == nil and legacy.keepGold ~= nil then db.keepGold = legacy.keepGold end
            if db.autoDepositGuild == nil and legacy.autoDepositGuild ~= nil then db.autoDepositGuild = legacy.autoDepositGuild end
            if db.autoDepositAccount == nil and legacy.autoDepositAccount ~= nil then db.autoDepositAccount = legacy.autoDepositAccount end
            if db.buttonLocked == nil and legacy.buttonLocked ~= nil then db.buttonLocked = legacy.buttonLocked end
            if db.buttonPoint == nil and legacy.buttonPoint ~= nil then db.buttonPoint = legacy.buttonPoint end
            if db.buttonRelativePoint == nil and legacy.buttonRelativePoint ~= nil then db.buttonRelativePoint = legacy.buttonRelativePoint end
            if db.buttonX == nil and legacy.buttonX ~= nil then db.buttonX = legacy.buttonX end
            if db.buttonY == nil and legacy.buttonY ~= nil then db.buttonY = legacy.buttonY end
        end

        db._migratedStandalone = true
    end

    if db.keepGold == nil then db.keepGold = DEFAULT_KEEP end
    if db.autoDepositGuild == nil then db.autoDepositGuild = false end
    if db.autoDepositAccount == nil then db.autoDepositAccount = false end
    if db.buttonLocked == nil then db.buttonLocked = false end

    if db.buttonPositionVersion ~= POSITION_VERSION then
        db.buttonPoint = db.buttonPoint or DEFAULT_POINT
        db.buttonRelativePoint = db.buttonRelativePoint or db.buttonPoint or DEFAULT_POINT
        db.buttonX = db.buttonX or DEFAULT_X
        db.buttonY = db.buttonY or DEFAULT_Y
        db.buttonPositionVersion = POSITION_VERSION
    end

    return db
end

local function GoldToCopper(gold)
    gold = tonumber(gold) or 0
    return math.floor(gold * 10000 + 0.5)
end

local function CopperToString(copper)
    copper = tonumber(copper) or 0

    local gold = math.floor(copper / 10000)
    local silver = math.floor((copper % 10000) / 100)
    local copperOnly = copper % 100

    return string.format("|cffffff00%dg|r |cffc0c0c0%ds|r |cffcd7f32%dc|r", gold, silver, copperOnly)
end

local function RunSoon(delay, callback)
    if C_Timer and C_Timer.After then
        C_Timer.After(delay or 0, callback)
    else
        callback()
    end
end

local function SafeIsShown(frame)
    if not frame or type(frame.IsShown) ~= "function" then
        return false
    end

    local ok, shown = pcall(frame.IsShown, frame)
    return ok and shown
end

local function GetGuildBankerInteractionType()
    if Enum and Enum.PlayerInteractionType and Enum.PlayerInteractionType.GuildBanker then
        return Enum.PlayerInteractionType.GuildBanker
    end

    return nil
end

local function GetAccountBankerInteractionType()
    if Enum and Enum.PlayerInteractionType and Enum.PlayerInteractionType.AccountBanker then
        return Enum.PlayerInteractionType.AccountBanker
    end

    return nil
end

local function IsGuildBankerInteraction(interactionType)
    local guildBankerType = GetGuildBankerInteractionType()
    return guildBankerType ~= nil and interactionType == guildBankerType
end

local function IsAccountBankerInteraction(interactionType)
    local accountBankerType = GetAccountBankerInteractionType()
    return accountBankerType ~= nil and interactionType == accountBankerType
end

local function GetAccountBankType()
    if Enum and Enum.BankType and Enum.BankType.Account ~= nil then
        return Enum.BankType.Account
    end

    return 2
end

local function CanDepositAccountMoney()
    if not C_Bank or type(C_Bank.CanDepositMoney) ~= "function" then
        return false
    end

    local ok, canDeposit = pcall(C_Bank.CanDepositMoney, GetAccountBankType())
    return ok and canDeposit
end

local function IsAccountBankPanelShown()
    return SafeIsShown(_G.AccountBankPanel)
end

local function IsGuildBankFrameShown()
    return SafeIsShown(_G.GuildBankFrame)
end

local function GetCurrentBankType()
    if bankSessionOpen and currentBankType then
        if currentBankType == BANK_TYPE_GUILD then
            if IsGuildBankFrameShown() then
                return BANK_TYPE_GUILD
            end

            return nil
        end

        if currentBankType == BANK_TYPE_ACCOUNT then
            if IsAccountBankPanelShown()
               or CanDepositAccountMoney()
               or (Now() - (lastBankSignalAt or 0)) <= ACCOUNT_BANK_SIGNAL_GRACE
            then
                return BANK_TYPE_ACCOUNT
            end

            return nil
        end

        return currentBankType
    end

    if IsGuildBankFrameShown() then
        return BANK_TYPE_GUILD
    end

    if IsAccountBankPanelShown() then
        return BANK_TYPE_ACCOUNT
    end

    return nil
end

local function IsBankSessionOpen()
    return GetCurrentBankType() ~= nil
end

local function GetBankName(bankType)
    if bankType == BANK_TYPE_ACCOUNT then
        return T("GD_BANK_ACCOUNT", "Warband bank")
    end

    return T("GD_BANK_GUILD", "guild bank")
end

local function ResolveAutoBankType(arg)
    arg = Trim(arg):lower()

    if arg == "account" or arg == "warband" or arg == "warbank" or arg == "отряд" or arg == "отряда" or arg == "банкотряда" then
        return BANK_TYPE_ACCOUNT
    end

    if arg == "guild" or arg == "gbank" or arg == "guildbank" or arg == "гильд" or arg == "гильдбанк" or arg == "гильдейский" then
        return BANK_TYPE_GUILD
    end

    return GetCurrentBankType() or BANK_TYPE_GUILD
end

local function IsAutoDepositEnabled(bankType)
    local db = EnsureDB()

    if bankType == BANK_TYPE_ACCOUNT then
        return db.autoDepositAccount
    end

    return db.autoDepositGuild
end

local function SetAutoDepositEnabled(bankType, enabled)
    local db = EnsureDB()

    if bankType == BANK_TYPE_ACCOUNT then
        db.autoDepositAccount = enabled and true or false
    else
        db.autoDepositGuild = enabled and true or false
    end
end

local function SaveButtonPosition()
    if not button then
        return
    end

    local point, _, relativePoint, x, y = button:GetPoint(1)
    local db = EnsureDB()

    db.buttonPoint = point or DEFAULT_POINT
    db.buttonRelativePoint = relativePoint or db.buttonPoint
    db.buttonX = x or DEFAULT_X
    db.buttonY = y or DEFAULT_Y
    db.buttonPositionVersion = POSITION_VERSION
end

local function RestoreButtonPosition()
    if not button then
        return
    end

    local db = EnsureDB()

    button:ClearAllPoints()
    button:SetPoint(
        db.buttonPoint or DEFAULT_POINT,
        UIParent,
        db.buttonRelativePoint or db.buttonPoint or DEFAULT_POINT,
        db.buttonX or DEFAULT_X,
        db.buttonY or DEFAULT_Y
    )
end

local function UpdateButtonLockVisual()
    if not button then
        return
    end

    local db = EnsureDB()

    if button.LockTexture then
        button.LockTexture:SetShown(db.buttonLocked)
    end
end

local function HideButton()
    if button then
        button:Hide()
    end
end

local function ShowButton()
    if not IsModuleEnabled() then
        HideButton()
        return
    end

    if not button then
        return
    end

    RestoreButtonPosition()
    button:SetFrameStrata("TOOLTIP")
    button:SetFrameLevel(9999)
    UpdateButtonLockVisual()
    button:Show()

    if button.Raise then
        button:Raise()
    end
end

local function UpdateButton()
    if not IsModuleEnabled() then
        HideButton()
        return
    end

    if IsBankSessionOpen() then
        ShowButton()
    else
        HideButton()
    end
end

local function DepositGold(requestedBankType)
    if not IsModuleEnabled() then
        print(ERROR_PREFIX .. " " .. T("GD_ERR_MODULE_DISABLED", "Gold Depositor is disabled in AhUI settings."))
        return
    end

    local db = EnsureDB()
    local bankType = requestedBankType or GetCurrentBankType()

    if not bankType then
        print(ERROR_PREFIX .. " " .. T("GD_ERR_BANK_NOT_OPEN", "Bank is not open!"))
        return
    end

    if bankType == BANK_TYPE_GUILD and type(DepositGuildBankMoney) ~= "function" then
        print(ERROR_PREFIX .. " " .. T("GD_ERR_GUILD_API", "DepositGuildBankMoney API is not available in this client."))
        return
    end

    if bankType == BANK_TYPE_ACCOUNT then
        if not C_Bank or type(C_Bank.DepositMoney) ~= "function" then
            print(ERROR_PREFIX .. " " .. T("GD_ERR_ACCOUNT_API", "C_Bank.DepositMoney API is not available in this client."))
            return
        end

        if not CanDepositAccountMoney() and not IsAccountBankPanelShown() then
            print(ERROR_PREFIX .. " " .. T("GD_ERR_ACCOUNT_BANK_UNAVAILABLE", "Warband bank is not open or cannot accept gold right now."))
            return
        end
    end

    if depositInProgress then
        print(PREFIX .. " " .. T("GD_TRANSFER_IN_PROGRESS", "Transfer is already in progress..."))
        return
    end

    local keepCopper = GoldToCopper(db.keepGold)
    local currentMoney = GetMoney()

    if currentMoney <= keepCopper then
        print(string.format(
            "%s " .. T("GD_NOTHING_TO_DEPOSIT", "Character has %s — less than or equal to %sg. Nothing to deposit."),
            PREFIX,
            CopperToString(currentMoney),
            tostring(db.keepGold)
        ))
        return
    end

    local depositAmount = currentMoney - keepCopper
    depositInProgress = true

    print(string.format(
        "%s " .. T("GD_DEPOSITING", "Depositing %s into %s..."),
        PREFIX,
        CopperToString(depositAmount),
        GetBankName(bankType)
    ))

    local ok, err

    if bankType == BANK_TYPE_ACCOUNT then
        ok, err = pcall(C_Bank.DepositMoney, GetAccountBankType(), depositAmount)
    else
        ok, err = pcall(DepositGuildBankMoney, depositAmount)
    end

    if not ok then
        depositInProgress = false
        print(ERROR_PREFIX .. " " .. T("GD_ERR_DEPOSIT_FAILED", "Transfer failed. Open the correct bank and try again."))

        if err then
            print(ERROR_PREFIX .. " " .. string.format(T("GD_ERR_DETAIL", "Error: %s"), tostring(err)))
        end

        return
    end

    RunSoon(0.5, function()
        depositInProgress = false

        local newMoney = GetMoney()
        print(string.format(
            "%s " .. T("GD_DONE", "Done! Character has left: %s"),
            OK_PREFIX,
            CopperToString(newMoney)
        ))
    end)
end

local function QueueAutoDeposit(bankType)
    bankType = bankType or GetCurrentBankType()

    if not bankType then
        return
    end

    if not IsAutoDepositEnabled(bankType) then
        return
    end

    if autoDepositQueued then
        return
    end

    autoDepositQueued = true
    autoDepositToken = autoDepositToken + 1

    local token = autoDepositToken
    local attempts = 0

    local function TryAutoDeposit()
        if token ~= autoDepositToken then
            return
        end

        attempts = attempts + 1

        if not IsAutoDepositEnabled(bankType) then
            autoDepositQueued = false
            return
        end

        if GetCurrentBankType() == bankType then
            autoDepositQueued = false
            DepositGold(bankType)
            return
        end

        if attempts < 10 then
            RunSoon(0.25, TryAutoDeposit)
        else
            autoDepositQueued = false
        end
    end

    RunSoon(0.35, TryAutoDeposit)
end

local function ToggleAutoDeposit(bankType)
    bankType = bankType or GetCurrentBankType() or BANK_TYPE_GUILD

    local enabled = not IsAutoDepositEnabled(bankType)
    SetAutoDepositEnabled(bankType, enabled)

    if enabled then
        print(OK_PREFIX .. " " .. string.format(T("GD_AUTO_ON", "Auto-deposit for %s is ON."), GetBankName(bankType)))
        UpdateButtonLockVisual()

        if GetCurrentBankType() == bankType then
            QueueAutoDeposit(bankType)
        end
    else
        autoDepositQueued = false
        autoDepositToken = autoDepositToken + 1
        print(ERROR_PREFIX .. " " .. string.format(T("GD_AUTO_OFF", "Auto-deposit for %s is OFF."), GetBankName(bankType)))
        UpdateButtonLockVisual()
    end
end

local function ToggleButtonLock()
    local db = EnsureDB()
    db.buttonLocked = not db.buttonLocked
    UpdateButtonLockVisual()

    if db.buttonLocked then
        print(OK_PREFIX .. " " .. T("GD_BUTTON_LOCKED", "Button position locked."))
    else
        print(PREFIX .. " " .. T("GD_BUTTON_UNLOCKED", "Button position unlocked. Drag the button with left mouse button."))
    end
end

local function ApplyKeepGoldValue(value)
    local amount = tonumber(value)

    if amount and amount >= 0 then
        local db = EnsureDB()
        db.keepGold = amount
        print(string.format("%s " .. T("GD_KEEP_SET", "Now keeping %sg on the character."), PREFIX, tostring(amount)))
        UpdateButton()
    else
        print(ERROR_PREFIX .. " " .. T("GD_ERR_INVALID_AMOUNT", "Enter a valid gold amount."))
    end
end

local function StyleButtonText(frame)
    if not frame or type(frame.GetFontString) ~= "function" then
        return
    end

    local fs = frame:GetFontString()
    if fs and type(fs.SetFont) == "function" then
        fs:SetFont(FONT, 12, "")
    end
end

local function CreateKeepGoldPopup()
    if keepPopup then
        return keepPopup
    end

    local f = CreateFrame("Frame", "AhUIGoldDepositorKeepPopup", UIParent, "BackdropTemplate")
    f:SetSize(340, 150)
    f:SetPoint("CENTER", UIParent, "CENTER", 0, 0)
    f:SetFrameStrata("DIALOG")
    f:SetFrameLevel(100)
    f:SetClampedToScreen(true)
    f:SetMovable(true)
    f:EnableMouse(true)
    f:RegisterForDrag("LeftButton")
    f:SetBackdrop({
        bgFile = "Interface\\Buttons\\WHITE8x8",
        edgeFile = "Interface\\Buttons\\WHITE8x8",
        edgeSize = 1,
    })
    f:SetBackdropColor(0, 0, 0, 0.95)
    f:SetBackdropBorderColor(1, 1, 1, 1)
    f:Hide()

    f:SetScript("OnDragStart", function(self)
        self:StartMoving()
    end)

    f:SetScript("OnDragStop", function(self)
        self:StopMovingOrSizing()
    end)

    local title = f:CreateFontString(nil, "OVERLAY")
    title:SetFont(FONT, 16, "OUTLINE")
    title:SetTextColor(1, 1, 1)
    title:SetPoint("TOPLEFT", f, "TOPLEFT", 14, -12)
    title:SetText(T("GD_TITLE", "AhUI Gold"))
    f.Title = title

    local text = f:CreateFontString(nil, "OVERLAY")
    text:SetFont(FONT, 13, "")
    text:SetTextColor(0.9, 0.9, 0.9)
    text:SetPoint("TOPLEFT", title, "BOTTOMLEFT", 0, -10)
    text:SetText(T("GD_KEEP_POPUP_TEXT", "How much gold should remain in your bags?"))
    f.Text = text

    local editBox = CreateFrame("EditBox", nil, f, "InputBoxTemplate")
    editBox:SetSize(120, 28)
    editBox:SetPoint("TOPLEFT", text, "BOTTOMLEFT", 0, -10)
    editBox:SetAutoFocus(false)
    editBox:SetNumeric(false)
    editBox:SetFont(FONT, 15, "")
    editBox:SetTextColor(1, 1, 1)
    editBox:SetJustifyH("LEFT")
    f.EditBox = editBox

    local suffix = f:CreateFontString(nil, "OVERLAY")
    suffix:SetFont(FONT, 13, "")
    suffix:SetTextColor(1, 0.82, 0)
    suffix:SetPoint("LEFT", editBox, "RIGHT", 8, 0)
    suffix:SetText("g")
    f.Suffix = suffix

    local ok = CreateFrame("Button", nil, f, "UIPanelButtonTemplate")
    ok:SetSize(96, 24)
    ok:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", -14, 14)
    ok:SetText(ACCEPT or "OK")
    StyleButtonText(ok)
    f.OkButton = ok

    local cancel = CreateFrame("Button", nil, f, "UIPanelButtonTemplate")
    cancel:SetSize(96, 24)
    cancel:SetPoint("RIGHT", ok, "LEFT", -8, 0)
    cancel:SetText(CANCEL or "Cancel")
    StyleButtonText(cancel)
    f.CancelButton = cancel

    local function AcceptValue()
        ApplyKeepGoldValue(editBox:GetText())
        f:Hide()
    end

    ok:SetScript("OnClick", AcceptValue)
    cancel:SetScript("OnClick", function()
        f:Hide()
    end)

    editBox:SetScript("OnEnterPressed", AcceptValue)
    editBox:SetScript("OnEscapePressed", function()
        f:Hide()
    end)

    f:SetScript("OnShow", function(self)
        local db = EnsureDB()
        editBox:SetText(tostring(db.keepGold or DEFAULT_KEEP))
        editBox:SetFocus()
        editBox:HighlightText()
    end)

    f:SetScript("OnHide", function()
        editBox:ClearFocus()
    end)

    keepPopup = f
    return keepPopup
end

local function OpenKeepGoldPopup()
    CreateKeepGoldPopup():Show()
end

local function ColorText(text, color)
    return color .. tostring(text) .. RESET_COLOR
end

local function KeyText(text)
    return ColorText(text, KEY_COLOR)
end

local function EnabledStatus(enabled)
    if enabled then
        return ColorText(T("GD_STATUS_ON", "ON"), ON_COLOR)
    end

    return ColorText(T("GD_STATUS_OFF", "OFF"), OFF_COLOR)
end

local function PositionStatus(locked)
    if locked then
        return ColorText(T("GD_POS_STATUS_LOCKED", "LOCKED"), OFF_COLOR)
    end

    return ColorText(T("GD_POS_STATUS_UNLOCKED", "UNLOCKED"), ON_COLOR)
end

local function TooltipLine(text, size, r, g, b)
    if Tooltip then
        Tooltip:AddLine(text, size, r, g, b)
    end
end

local function TooltipAction(keys, text)
    TooltipLine(KeyText(keys) .. ColorText(" — " .. text, TEXT_COLOR), 12, 1, 1, 1)
end

local function TooltipStatus(name, value)
    TooltipLine(ColorText(name .. ": ", DIM_COLOR) .. value, 12, 1, 1, 1)
end

local function ShowAhUITooltip(owner)
    if not Tooltip then
        return
    end

    local db = EnsureDB()
    local bankType = GetCurrentBankType()
    local bankName = bankType and GetBankName(bankType) or T("GD_BANK_NOT_OPEN", "bank is not open")
    local currentAutoText = ""

    if bankType then
        currentAutoText = " " .. ColorText("[" .. EnabledStatus(IsAutoDepositEnabled(bankType)) .. "]", DIM_COLOR)
    end

    Tooltip:Clear()
    TooltipLine(T("GD_TITLE", "AhUI Gold"), 14, 1, 1, 1)
    TooltipStatus(T("GD_TT_CURRENT_BANK", "Current bank"), ColorText(bankName, INFO_COLOR))
    TooltipLine(" ", 4, 1, 1, 1)
    TooltipAction(T("GD_KEY_LMB", "LMB"), T("GD_TT_DEPOSIT", "deposit gold"))
    TooltipAction(T("GD_KEY_ALT_LMB", "Alt + LMB"), T("GD_TT_KEEP", "change gold to keep in bags"))
    TooltipAction(T("GD_KEY_SHIFT_LMB", "Shift + LMB"), T("GD_TT_AUTO_ACCOUNT", "warband bank auto-deposit") .. " " .. EnabledStatus(db.autoDepositAccount))
    TooltipAction(T("GD_KEY_DRAG_LMB", "Hold LMB"), T("GD_TT_MOVE", "move button"))
    TooltipAction(T("GD_KEY_MMB", "MMB"), db.buttonLocked and T("GD_TT_UNLOCK", "unlock position") or T("GD_TT_LOCK", "lock position"))
    TooltipAction(T("GD_KEY_RMB", "RMB"), T("GD_TT_AUTO_CURRENT", "current bank auto-deposit") .. currentAutoText)
    TooltipAction(T("GD_KEY_SHIFT_RMB", "Shift + RMB"), T("GD_TT_AUTO_GUILD", "guild bank auto-deposit") .. " " .. EnabledStatus(db.autoDepositGuild))
    TooltipLine(" ", 4, 1, 1, 1)
    TooltipStatus(T("GD_TT_POSITION", "Position"), PositionStatus(db.buttonLocked))
    TooltipStatus(T("GD_TT_AUTO_GUILD_STATUS", "Guild bank auto"), EnabledStatus(db.autoDepositGuild))
    TooltipStatus(T("GD_TT_AUTO_ACCOUNT_STATUS", "Warband bank auto"), EnabledStatus(db.autoDepositAccount))
    TooltipStatus(T("GD_TT_KEEP_STATUS", "Keep"), ColorText(tostring(db.keepGold) .. "g", KEY_COLOR))
    Tooltip:ShowSmart(owner, 10)
end

local function CreateButton()
    if not IsModuleEnabled() then
        HideButton()
        return nil
    end

    if button then
        UpdateButton()
        return button
    end

    button = CreateFrame("Button", "AhUIGoldDepositorButton", UIParent)
    button:SetSize(BUTTON_SIZE, BUTTON_SIZE)
    button:SetClampedToScreen(true)
    button:SetMovable(true)
    button:EnableMouse(true)
    button:RegisterForClicks("LeftButtonUp", "RightButtonUp", "MiddleButtonUp")
    button:RegisterForDrag("LeftButton")
    button:Hide()

    local icon = button:CreateTexture(nil, "ARTWORK")
    icon:SetAllPoints()

    local iconOk = false

    if type(icon.SetAtlas) == "function" then
        iconOk = pcall(icon.SetAtlas, icon, "Mobile-TreasureIcon", true)
    end

    if not iconOk then
        icon:SetTexture("Interface\\Icons\\INV_Misc_Coin_02")
    end

    button.Icon = icon

    local lockTexture = button:CreateTexture(nil, "OVERLAY")
    lockTexture:SetSize(18, 18)
    lockTexture:SetPoint("TOPRIGHT", -3, -3)
    lockTexture:SetTexture("Interface\\Buttons\\LockButton-Locked-Up")
    lockTexture:Hide()
    button.LockTexture = lockTexture

    button:SetScript("OnDragStart", function(self)
        local db = EnsureDB()

        if db.buttonLocked then
            return
        end

        self.wasDragged = true
        self:StartMoving()
    end)

    button:SetScript("OnDragStop", function(self)
        self:StopMovingOrSizing()
        SaveButtonPosition()

        RunSoon(0.15, function()
            if self then
                self.wasDragged = false
            end
        end)
    end)

    button:SetScript("OnMouseDown", function(self)
        if self.Icon then
            self.Icon:SetScale(0.92)
        end
    end)

    button:SetScript("OnMouseUp", function(self)
        if self.Icon then
            self.Icon:SetScale(1)
        end
    end)

    button:SetScript("OnClick", function(self, mouseButton)
        if self.wasDragged then
            return
        end

        if mouseButton == "LeftButton" then
            if IsAltKeyDown and IsAltKeyDown() then
                OpenKeepGoldPopup()
            elseif IsShiftKeyDown and IsShiftKeyDown() then
                ToggleAutoDeposit(BANK_TYPE_ACCOUNT)
            else
                DepositGold()
            end
        elseif mouseButton == "MiddleButton" then
            ToggleButtonLock()
        elseif mouseButton == "RightButton" then
            if IsShiftKeyDown and IsShiftKeyDown() then
                ToggleAutoDeposit(BANK_TYPE_GUILD)
            else
                ToggleAutoDeposit(GetCurrentBankType() or BANK_TYPE_GUILD)
            end
        end

        if self:IsMouseOver() then
            ShowAhUITooltip(self)
        end
    end)

    button:SetScript("OnEnter", ShowAhUITooltip)

    button:SetScript("OnLeave", function(self)
        UpdateButtonLockVisual()

        if self.Icon then
            self.Icon:SetScale(1)
        end

        if Tooltip then
            Tooltip:Clear()
        end
    end)

    RestoreButtonPosition()
    UpdateButtonLockVisual()
    UpdateButton()

    return button
end

local function EnsureButton()
    if not IsModuleEnabled() then
        HideButton()
        return
    end

    CreateButton()
    UpdateButton()
end

local function MarkBankOpen(bankType)
    bankSessionOpen = true
    currentBankType = bankType
    lastBankSignalAt = Now()
    EnsureButton()
end

local function MarkBankClosed(bankType)
    if bankType and currentBankType and bankType ~= currentBankType then
        return
    end

    bankSessionOpen = false
    currentBankType = nil
    autoDepositQueued = false
    autoDepositToken = autoDepositToken + 1
    HideButton()
end

local function OnBankSignal(bankType)
    if not IsModuleEnabled() then
        HideButton()
        return
    end

    MarkBankOpen(bankType)
    QueueAutoDeposit(bankType)

    RunSoon(0.10, EnsureButton)
    RunSoon(0.35, EnsureButton)
    RunSoon(0.75, EnsureButton)
end

local function OnGuildBankSignal()
    OnBankSignal(BANK_TYPE_GUILD)
end

local function OnAccountBankSignal()
    OnBankSignal(BANK_TYPE_ACCOUNT)
end

local function TryAccountBankSignal()
    if IsAccountBankPanelShown() or CanDepositAccountMoney() then
        OnAccountBankSignal()
    end
end

local function InstallAccountBankHooks()
    if accountBankHooksInstalled then
        return
    end

    local panel = _G.AccountBankPanel

    if not panel or type(panel.HookScript) ~= "function" then
        return
    end

    accountBankHooksInstalled = true

    panel:HookScript("OnShow", function()
        OnAccountBankSignal()
    end)

    panel:HookScript("OnHide", function()
        if currentBankType == BANK_TYPE_ACCOUNT then
            MarkBankClosed(BANK_TYPE_ACCOUNT)
        end
    end)

    local itemDepositFrame = panel.ItemDepositFrame
    local checkbox = itemDepositFrame and itemDepositFrame.IncludeReagentsCheckbox

    if checkbox and type(checkbox.HookScript) == "function" then
        checkbox:HookScript("OnShow", function()
            OnAccountBankSignal()
        end)

        checkbox:HookScript("OnHide", function()
            if currentBankType == BANK_TYPE_ACCOUNT then
                RunSoon(0.1, function()
                    if not IsAccountBankPanelShown() and not CanDepositAccountMoney() then
                        MarkBankClosed(BANK_TYPE_ACCOUNT)
                    end
                end)
            end
        end)
    end
end

local function ResetButtonPosition()
    local db = EnsureDB()
    db.buttonPoint = DEFAULT_POINT
    db.buttonRelativePoint = DEFAULT_POINT
    db.buttonX = DEFAULT_X
    db.buttonY = DEFAULT_Y
    db.buttonPositionVersion = POSITION_VERSION
    RestoreButtonPosition()
    UpdateButton()
    print(OK_PREFIX .. " " .. T("GD_RESET_DONE", "Button position reset."))
end

local function PrintHelp()
    local db = EnsureDB()

    print(PREFIX .. " " .. T("GD_HELP_TITLE", "Commands:"))
    print(T("GD_HELP_DEPOSIT", "  /gd deposit          — deposit gold into the open bank: guild bank or warband bank"))
    print(T("GD_HELP_AUTO", "  /gd auto             — toggle auto-deposit for the current open bank; without an open bank, guild bank is used"))
    print(T("GD_HELP_AUTO_GUILD", "  /gd auto guild       — toggle guild bank auto-deposit"))
    print(T("GD_HELP_AUTO_WARBAND", "  /gd auto warband     — toggle warband bank auto-deposit"))
    print(T("GD_HELP_LOCK", "  /gd lock             — lock/unlock button position"))
    print(T("GD_HELP_RESET", "  /gd reset            — reset button position"))
    print(string.format(T("GD_HELP_KEEP", "  /gd keep <amount>    — how much gold to keep, current: %sg"), tostring(db.keepGold)))
    print(T("GD_HELP_BUTTON", "  /gd button           — refresh the button"))
    print(T("GD_HELP_STATUS", "  /gd status           — show current settings"))
    print(T("GD_HELP_ALIAS", "  /ahuigd              — full alias for /gd"))
    print(T("GD_HELP_BUTTON_HINT", "  Button: LMB deposit, Alt+LMB keep amount, Shift+LMB warband bank auto, MMB lock, RMB current bank auto, Shift+RMB guild bank auto."))
end

local function PrintStatus()
    local db = EnsureDB()
    local keepGold = db.keepGold or DEFAULT_KEEP
    local current = GetMoney()
    local willDeposit = math.max(0, current - GoldToCopper(keepGold))
    local bankType = GetCurrentBankType()
    local accountMoney = nil

    if C_Bank and type(C_Bank.FetchDepositedMoney) == "function" then
        local ok, money = pcall(C_Bank.FetchDepositedMoney, GetAccountBankType())

        if ok then
            accountMoney = money
        end
    end

    print(PREFIX .. " " .. T("GD_STATUS_TITLE", "Status:"))
    print(T("GD_STATUS_CURRENT", "  On character:           ") .. CopperToString(current))
    print(T("GD_STATUS_KEEP", "  Minimum kept:           ") .. tostring(keepGold) .. "g")
    print(T("GD_STATUS_OPEN_BANK", "  Open bank:              ") .. (bankType and GetBankName(bankType) or T("GD_NO", "none")))
    print(T("GD_STATUS_AUTO_GUILD", "  Guild bank auto:        ") .. (db.autoDepositGuild and T("GD_ENABLED", "enabled") or T("GD_DISABLED", "disabled")))
    print(T("GD_STATUS_AUTO_ACCOUNT", "  Warband bank auto:      ") .. (db.autoDepositAccount and T("GD_ENABLED", "enabled") or T("GD_DISABLED", "disabled")))
    print(T("GD_STATUS_POSITION", "  Button position:        ") .. (db.buttonLocked and T("GD_LOCKED", "locked") or T("GD_UNLOCKED", "unlocked")))
    print(T("GD_STATUS_LAST_SIGNAL", "  Last signal:            ") .. string.format("%.2f", lastBankSignalAt or 0))
    print(T("GD_STATUS_WILL_DEPOSIT", "  Will deposit:           ") .. CopperToString(willDeposit))

    if accountMoney ~= nil then
        print(T("GD_STATUS_ACCOUNT_BANK", "  In warband bank:        ") .. CopperToString(accountMoney))
    end
end

local function HandleCommand(input)
    EnsureDB()

    input = Trim(input)

    if not IsModuleEnabled() then
        print(ERROR_PREFIX .. " " .. T("GD_ERR_MODULE_DISABLED", "Gold Depositor is disabled in AhUI settings."))
        return
    end

    local cmd, arg = input:match("^(%S*)%s*(.*)$")
    cmd = (cmd or ""):lower()
    arg = arg or ""

    if cmd == "" or cmd == "help" then
        PrintHelp()
    elseif cmd == "deposit" then
        DepositGold()
    elseif cmd == "auto" then
        ToggleAutoDeposit(ResolveAutoBankType(arg))
    elseif cmd == "lock" then
        ToggleButtonLock()
    elseif cmd == "reset" then
        ResetButtonPosition()
    elseif cmd == "button" then
        EnsureButton()

        if IsBankSessionOpen() then
            print(OK_PREFIX .. " " .. T("GD_BUTTON_REFRESHED", "Button refreshed."))
        else
            print(ERROR_PREFIX .. " " .. T("GD_ERR_BUTTON_BANK_NOT_OPEN", "Bank is not open. Button will appear after opening a guild bank or warband bank."))
        end
    elseif cmd == "keep" then
        local amount = tonumber(arg)

        if amount and amount >= 0 then
            local db = EnsureDB()
            db.keepGold = amount
            print(string.format("%s " .. T("GD_KEEP_SET", "Now keeping %sg on the character."), PREFIX, tostring(amount)))
            UpdateButton()
        else
            print(ERROR_PREFIX .. " " .. T("GD_ERR_KEEP_USAGE", "Enter a valid amount: /gd keep 200"))
        end
    elseif cmd == "status" then
        PrintStatus()
    else
        print(ERROR_PREFIX .. " " .. T("GD_ERR_UNKNOWN_COMMAND", "Unknown command. Type /gd help"))
    end
end

SLASH_AHUIGOLDDEPOSITOR1 = "/ahuigd"
SLASH_AHUIGOLDDEPOSITOR2 = "/gd"
SlashCmdList["AHUIGOLDDEPOSITOR"] = HandleCommand

local eventFrame = CreateFrame("Frame")
eventFrame:RegisterEvent("ADDON_LOADED")
eventFrame:RegisterEvent("PLAYER_LOGIN")
eventFrame:RegisterEvent("GUILDBANKFRAME_OPENED")
eventFrame:RegisterEvent("GUILDBANKFRAME_CLOSED")
eventFrame:RegisterEvent("GUILDBANK_UPDATE_MONEY")
eventFrame:RegisterEvent("GUILDBANK_UPDATE_TABS")
eventFrame:RegisterEvent("BANKFRAME_OPENED")
eventFrame:RegisterEvent("BANKFRAME_CLOSED")
eventFrame:RegisterEvent("ACCOUNT_MONEY")
eventFrame:RegisterEvent("PLAYER_INTERACTION_MANAGER_FRAME_SHOW")
eventFrame:RegisterEvent("PLAYER_INTERACTION_MANAGER_FRAME_HIDE")
eventFrame:RegisterEvent("PLAYER_REGEN_ENABLED")

eventFrame:SetScript("OnEvent", function(_, event, arg1)
    if event == "ADDON_LOADED" then
        if arg1 == ADDON_NAME then
            EnsureDB()
            if IsModuleEnabled() then
                CreateButton()
            else
                HideButton()
            end
        elseif arg1 == "Blizzard_BankUI" and IsModuleEnabled() then
            InstallAccountBankHooks()
        end
        return
    elseif event == "PLAYER_LOGIN" then
        EnsureDB()
        if IsModuleEnabled() then
            CreateButton()
            InstallAccountBankHooks()
        else
            HideButton()
        end
        return
    end

    if not IsModuleEnabled() then
        HideButton()
        return
    end

    if event == "GUILDBANKFRAME_OPENED" then
        OnGuildBankSignal()
    elseif event == "GUILDBANK_UPDATE_MONEY" or event == "GUILDBANK_UPDATE_TABS" then
        if IsGuildBankFrameShown() then
            if currentBankType ~= BANK_TYPE_GUILD then
                OnGuildBankSignal()
            else
                UpdateButton()
            end
        else
            if currentBankType == BANK_TYPE_GUILD then
                MarkBankClosed(BANK_TYPE_GUILD)
            else
                UpdateButton()
            end
        end
    elseif event == "GUILDBANKFRAME_CLOSED" then
        MarkBankClosed(BANK_TYPE_GUILD)
    elseif event == "BANKFRAME_OPENED" then
        InstallAccountBankHooks()
        RunSoon(0.10, TryAccountBankSignal)
        RunSoon(0.35, TryAccountBankSignal)
    elseif event == "BANKFRAME_CLOSED" then
        if currentBankType == BANK_TYPE_ACCOUNT then
            MarkBankClosed(BANK_TYPE_ACCOUNT)
        end
    elseif event == "ACCOUNT_MONEY" then
        InstallAccountBankHooks()

        if currentBankType == BANK_TYPE_ACCOUNT then
            UpdateButton()
        elseif IsAccountBankPanelShown() then
            RunSoon(0.10, TryAccountBankSignal)
        end
    elseif event == "PLAYER_INTERACTION_MANAGER_FRAME_SHOW" then
        if IsGuildBankerInteraction(arg1) then
            RunSoon(0.10, function()
                if IsGuildBankFrameShown() then
                    OnGuildBankSignal()
                end
            end)
        elseif IsAccountBankerInteraction(arg1) then
            RunSoon(0.10, TryAccountBankSignal)
            RunSoon(0.35, TryAccountBankSignal)
        else
            if currentBankType == BANK_TYPE_ACCOUNT and not IsAccountBankPanelShown() then
                MarkBankClosed(BANK_TYPE_ACCOUNT)
            else
                UpdateButton()
            end
        end
    elseif event == "PLAYER_INTERACTION_MANAGER_FRAME_HIDE" then
        if IsGuildBankerInteraction(arg1) then
            MarkBankClosed(BANK_TYPE_GUILD)
        elseif IsAccountBankerInteraction(arg1) then
            MarkBankClosed(BANK_TYPE_ACCOUNT)
        else
            if currentBankType == BANK_TYPE_ACCOUNT then
                RunSoon(0.10, function()
                    if not IsAccountBankPanelShown() and not CanDepositAccountMoney() then
                        MarkBankClosed(BANK_TYPE_ACCOUNT)
                    end
                end)
            else
                UpdateButton()
            end
        end
    elseif event == "PLAYER_REGEN_ENABLED" then
        UpdateButton()
    end
end)

local function ApplyEnabledState()
    EnsureDB()

    if not IsModuleEnabled() then
        bankSessionOpen = false
        currentBankType = nil
        autoDepositQueued = false
        autoDepositToken = autoDepositToken + 1
        HideButton()

        if keepPopup then
            keepPopup:Hide()
        end

        if Tooltip then
            Tooltip:Clear()
        end

        return
    end

    CreateButton()
    InstallAccountBankHooks()
    UpdateButton()
end

GD.IsEnabled = IsModuleEnabled
GD.ApplyEnabledState = ApplyEnabledState

GD.DepositGold = DepositGold
GD.ToggleAutoDeposit = ToggleAutoDeposit
GD.ResetButtonPosition = ResetButtonPosition
GD.UpdateButton = UpdateButton
GD.ShowButton = ShowButton
GD.HideButton = HideButton
GD.GetDB = EnsureDB
GD.HandleCommand = HandleCommand
