local NS = rawget(_G, "MCDVoiceCooldownNS") or {}
_G.MCDVoiceCooldownNS = NS

NS.Core = NS.Core or {}
NS.Core.MinimapButton = NS.Core.MinimapButton or {}

local MinimapButton = NS.Core.MinimapButton
local L = NS.L or function(key, ...) if select("#", ...) > 0 then return string.format(tostring(key), ...) end return tostring(key) end
local BUTTON_NAME = "MCDVoiceCooldownMinimapButton"
local DEFAULT_ANGLE = 225
local DEFAULT_RADIUS = 82
local ICON_PATH = NS.ADDON_ICON or "Interface\\AddOns\\MCDVoiceCooldown\\AppIcon.png"

local function GetDisplayName()
    return NS.ADDON_DISPLAY_NAME or L("ADDON_DISPLAY_NAME")
end

local function EnsureDB()
    local db = MCDVoiceCooldownDB
    if type(db) ~= "table" then
        db = {}
        MCDVoiceCooldownDB = db
    end

    if type(db.minimap) ~= "table" then
        db.minimap = {}
    end
    if db.minimap.angle == nil then
        db.minimap.angle = DEFAULT_ANGLE
    end
    if db.minimap.radius == nil then
        db.minimap.radius = DEFAULT_RADIUS
    end
    if db.minimap.hide == nil then
        db.minimap.hide = false
    end

    return db.minimap
end

local function Atan2(y, x)
    if math.atan2 then
        return math.atan2(y, x)
    end

    if x > 0 then
        return math.atan(y / x)
    elseif x < 0 and y >= 0 then
        return math.atan(y / x) + math.pi
    elseif x < 0 and y < 0 then
        return math.atan(y / x) - math.pi
    elseif x == 0 and y > 0 then
        return math.pi / 2
    elseif x == 0 and y < 0 then
        return -math.pi / 2
    end

    return 0
end

local function OpenMainFrame()
    if NS.UI and NS.UI.MainFrame and type(NS.UI.MainFrame.Open) == "function" then
        NS.UI.MainFrame:Open()
    else
        print("[MCD-CVA] " .. L("MSG_MAIN_NOT_READY"))
    end
end

local function OpenBlizzardOptions()
    if NS.Core and NS.Core.ConfigPanel and type(NS.Core.ConfigPanel.Open) == "function" then
        NS.Core.ConfigPanel:Open()
    else
        OpenMainFrame()
    end
end

function MinimapButton:UpdatePosition()
    if not self.button or not Minimap then
        return
    end

    local db = EnsureDB()
    local angle = tonumber(db.angle) or DEFAULT_ANGLE
    local radius = tonumber(db.radius) or DEFAULT_RADIUS
    local rad = math.rad(angle)

    self.button:ClearAllPoints()
    self.button:SetPoint("CENTER", Minimap, "CENTER", math.cos(rad) * radius, math.sin(rad) * radius)

    if db.hide then
        self.button:Hide()
    else
        self.button:Show()
    end
end

function MinimapButton:UpdateDragPosition()
    if not self.button or not Minimap then
        return
    end

    local mx, my = Minimap:GetCenter()
    local px, py = GetCursorPosition()
    local scale = Minimap:GetEffectiveScale() or 1
    px, py = px / scale, py / scale

    local angle = math.deg(Atan2(py - my, px - mx))
    EnsureDB().angle = angle
    self:UpdatePosition()
end

function MinimapButton:Initialize()
    if self.initialized then
        self:UpdatePosition()
        return
    end
    self.initialized = true

    if not Minimap then
        return
    end

    local button = CreateFrame("Button", BUTTON_NAME, Minimap)
    -- Keep the clickable button, the addon icon, the tracking border and the highlight
    -- all anchored by CENTER.  This avoids the icon drifting outside of the round
    -- minimap button frame on different UI scales / client versions.
    button:SetSize(32, 32)
    button:SetFrameStrata("MEDIUM")
    button:SetFrameLevel((Minimap:GetFrameLevel() or 0) + 8)
    button:RegisterForClicks("LeftButtonUp", "RightButtonUp")
    button:RegisterForDrag("LeftButton")
    button:SetClampedToScreen(true)
    button:EnableMouse(true)

    local icon = button:CreateTexture(nil, "ARTWORK")
    icon:SetSize(20, 20)
    icon:SetPoint("CENTER", button, "CENTER", 0, 0)
    icon:SetTexture(ICON_PATH)
    icon:SetTexCoord(0.08, 0.92, 0.08, 0.92)
    button.icon = icon

    local border = button:CreateTexture(nil, "OVERLAY")
    border:SetTexture("Interface\\Minimap\\MiniMap-TrackingBorder")
    border:SetSize(54, 54)
    border:SetPoint("CENTER", button, "CENTER", 1, -1)
    button.border = border

    local highlight = button:CreateTexture(nil, "HIGHLIGHT")
    highlight:SetTexture("Interface\\Minimap\\UI-Minimap-ZoomButton-Highlight")
    highlight:SetBlendMode("ADD")
    highlight:SetSize(32, 32)
    highlight:SetPoint("CENTER", button, "CENTER", 0, 0)

    button:SetScript("OnClick", function(_, mouseButton)
        if mouseButton == "RightButton" then
            OpenBlizzardOptions()
        else
            OpenMainFrame()
        end
    end)

    button:SetScript("OnDragStart", function()
        button:SetScript("OnUpdate", function()
            MinimapButton:UpdateDragPosition()
        end)
    end)

    button:SetScript("OnDragStop", function()
        button:SetScript("OnUpdate", nil)
        MinimapButton:UpdatePosition()
    end)

    button:SetScript("OnEnter", function(self)
        if not GameTooltip then
            return
        end
        GameTooltip:SetOwner(self, "ANCHOR_LEFT")
        GameTooltip:SetText(GetDisplayName(), 1, 0.82, 0)
        GameTooltip:AddLine(L("MINIMAP_LEFT"), 1, 1, 1)
        GameTooltip:AddLine(L("MINIMAP_RIGHT"), 1, 1, 1)
        GameTooltip:AddLine(L("MINIMAP_DRAG"), 0.7, 0.7, 0.7)
        GameTooltip:AddLine(L("MINIMAP_ICON_FILE"), 0.55, 0.75, 1)
        GameTooltip:Show()
    end)

    button:SetScript("OnLeave", function()
        if GameTooltip then
            GameTooltip:Hide()
        end
    end)

    self.button = button
    self:UpdatePosition()
end

function MinimapButton:Show()
    EnsureDB().hide = false
    self:UpdatePosition()
end

function MinimapButton:Hide()
    EnsureDB().hide = true
    if self.button then
        self.button:Hide()
    end
end
