local _, Addon = ...

local UI = {}
Addon.UI = UI
local L = Addon.L

local state = Addon.state
local mapFrame
local viewport
local canvas
local titleText
local statusText
local helpText
local minimapButton
local titleBar
local closeButton
local plusButton
local minusButton
local centerButton
local circleBorder
local circleMask
local DUNGEON_CHOICE_DIALOG = "MIYAMAP_DUNGEON_MAP_CHOICE"

local function SaveFramePosition()
    local point, relativeFrame, relativePoint, x, y = mapFrame:GetPoint(1)
    Addon.db.point = point
    Addon.db.relativeFrame = relativeFrame and relativeFrame:GetName() or "UIParent"
    Addon.db.relativePoint = relativePoint
    Addon.db.x = math.floor((x or 0) + 0.5)
    Addon.db.y = math.floor((y or 0) + 0.5)
end

local function RestoreFramePosition()
    local relativeFrame = _G[Addon.db.relativeFrame or "UIParent"] or UIParent
    mapFrame:ClearAllPoints()
    mapFrame:SetPoint(
        Addon.db.point or Addon.defaults.point,
        relativeFrame,
        Addon.db.relativePoint or Addon.defaults.relativePoint,
        Addon.db.x or Addon.defaults.x,
        Addon.db.y or Addon.defaults.y
    )
end

local function PositionMapModeButton()
    if not minimapButton then
        return
    end

    local parent = UIParent
    local frameLevel = 60
    minimapButton:ClearAllPoints()
    if state.replacementApplied and mapFrame then
        parent = UIParent
        frameLevel = mapFrame:GetFrameLevel() + 60
        minimapButton:SetParent(parent)
        minimapButton:SetPoint("BOTTOMRIGHT", mapFrame, "BOTTOMLEFT", -6, 0)
    elseif Minimap then
        parent = MinimapCluster or UIParent
        frameLevel = math.max(
            Minimap:GetFrameLevel() or 1,
            MinimapCluster and MinimapCluster:GetFrameLevel() or 1
        ) + 50
        minimapButton:SetParent(parent)
        local saved = Addon.db.minimapButtonPosition
        if type(saved) == "table" and tonumber(saved.x) and tonumber(saved.y) then
            minimapButton:SetPoint(
                "CENTER",
                Minimap,
                "CENTER",
                tonumber(saved.x),
                tonumber(saved.y)
            )
        else
            minimapButton:SetPoint("BOTTOMLEFT", Minimap, "BOTTOMLEFT", -3, -3)
        end
    else
        minimapButton:SetParent(parent)
        minimapButton:SetPoint("TOPRIGHT", UIParent, "TOPRIGHT", -12, -12)
    end
    minimapButton:SetFrameStrata("LOW")
    minimapButton:SetFrameLevel(frameLevel)
    minimapButton:SetShown(Addon.db.showButton)
end

local function SaveMinimapButtonPosition()
    if not minimapButton or not Minimap then
        return
    end

    local buttonX, buttonY = minimapButton:GetCenter()
    local minimapX, minimapY = Minimap:GetCenter()
    if not buttonX or not buttonY or not minimapX or not minimapY then
        return
    end

    Addon.db.minimapButtonPosition = {
        x = math.floor((buttonX - minimapX) + 0.5),
        y = math.floor((buttonY - minimapY) + 0.5),
    }
end

local function MakeHeaderButton(parent, text, width, onClick)
    local button = CreateFrame("Button", nil, parent, "UIPanelButtonTemplate")
    button:SetSize(width, 18)
    button:SetText(text)
    button:SetScript("OnClick", onClick)
    return button
end

function UI:ApplyReplacementMode(enabled, announce)
    enabled = not not enabled

    if enabled then
        if not Addon.db.replacementInitialized then
            Addon.db.point = "TOPRIGHT"
            Addon.db.relativeFrame = "Minimap"
            Addon.db.relativePoint = "TOPRIGHT"
            Addon.db.x = 8
            Addon.db.y = 8
            Addon.db.replacementInitialized = true
        end

        RestoreFramePosition()
        state.replacementApplied = true
        Addon.AddonButtons:SetEnabled(true)
        mapFrame:Show()
        if MinimapCluster then
            MinimapCluster:Hide()
        end
        if Minimap then
            Minimap:Hide()
        end
        if Addon.Gathering then
            Addon.Gathering:Apply()
        end
        C_Timer.After(0, function()
            if mapFrame:IsShown() then
                Addon.MapView:Rebuild(true)
            end
        end)
    else
        state.replacementApplied = false
        if Addon.Gathering then
            Addon.Gathering:Apply()
        end
        Addon.AddonButtons:SetEnabled(false)
        if MinimapCluster then
            MinimapCluster:Show()
        end
        if Minimap then
            Minimap:Show()
        end
        mapFrame:Hide()
    end

    if mapFrame then
        self:ApplyAppearance()
    end
    PositionMapModeButton()

    if announce then
        Addon:Print(
            enabled
                and L.REPLACEMENT_ENABLED
                or L.REPLACEMENT_DISABLED
        )
    end
end

function UI:SetReplacementMode(enabled, announce)
    enabled = not not enabled
    Addon.db.replaceMinimap = enabled
    if state.dungeonChoiceActive or Addon.db.dungeonMapChoicePrompted then
        state.dungeonMapChoice = enabled and "miyamap" or "minimap"
        Addon.db.lastDungeonMapChoice = state.dungeonMapChoice
    end
    self:ApplyReplacementMode(enabled, announce)
end

function UI:SelectDungeonMap(choice, announce)
    if not state.dungeonChoiceActive then
        return
    end

    choice = choice == "minimap" and "minimap" or "miyamap"
    state.dungeonMapChoice = choice
    Addon.db.lastDungeonMapChoice = choice
    Addon.db.replaceMinimap = choice == "miyamap"
    self:ApplyReplacementMode(choice == "miyamap", false)

    if announce then
        Addon:Print(
            choice == "miyamap"
                and L.DUNGEON_MIYAMAP_SAVED
                or L.DUNGEON_MINIMAP_SAVED
        )
    end
end

function UI:ConfirmDungeonMapChoice(choice)
    if not state.dungeonChoiceActive then
        return
    end

    Addon.db.dungeonMapChoicePrompted = true
    self:SelectDungeonMap(choice, true)
end

function UI:LeaveDungeonChoice()
    if not state.dungeonChoiceActive then
        return
    end

    state.dungeonChoiceActive = false
    state.dungeonMapChoice = nil
    state.dungeonInstanceID = nil
    state.dungeonChoiceGeneration = state.dungeonChoiceGeneration + 1
    StaticPopup_Hide(DUNGEON_CHOICE_DIALOG)
    self:ApplyReplacementMode(Addon.db.replaceMinimap, false)
end

function UI:HandlePlayerEnteringWorld()
    local inInstance, instanceType = IsInInstance()
    if not inInstance or instanceType ~= "party" then
        self:LeaveDungeonChoice()
        return
    end

    local dungeonName = GetInstanceInfo()
    local instanceID = tonumber(select(8, GetInstanceInfo())) or 0
    if state.dungeonChoiceActive and state.dungeonInstanceID == instanceID then
        return
    end
    if state.dungeonChoiceActive then
        self:LeaveDungeonChoice()
    end

    state.dungeonChoiceActive = true
    state.dungeonInstanceID = instanceID
    state.dungeonChoiceGeneration = state.dungeonChoiceGeneration + 1
    local generation = state.dungeonChoiceGeneration

    if Addon.db.dungeonMapChoicePrompted then
        self:SelectDungeonMap(Addon.db.lastDungeonMapChoice, false)
        return
    end

    C_Timer.After(0.40, function()
        local stillInInstance, stillInstanceType = IsInInstance()
        local currentInstanceID = tonumber(select(8, GetInstanceInfo())) or 0
        if not state.dungeonChoiceActive
            or generation ~= state.dungeonChoiceGeneration
            or not stillInInstance
            or stillInstanceType ~= "party"
            or (instanceID > 0 and currentInstanceID ~= instanceID)
        then
            return
        end

        StaticPopup_Show(DUNGEON_CHOICE_DIALOG, dungeonName or L.THIS_DUNGEON)
    end)
end

function UI:RegisterDungeonChoiceDialog()
    StaticPopupDialogs[DUNGEON_CHOICE_DIALOG] = {
        text = L.DUNGEON_CHOICE_TEXT,
        button1 = L.USE_MIYAMAP,
        button2 = L.NORMAL_MINIMAP,
        OnAccept = function()
            Addon.UI:ConfirmDungeonMapChoice("miyamap")
        end,
        OnCancel = function()
            Addon.UI:ConfirmDungeonMapChoice("minimap")
        end,
        timeout = 0,
        whileDead = true,
        hideOnEscape = false,
        preferredIndex = 3,
    }
end

function UI:ToggleReplacementMode(announce)
    self:SetReplacementMode(not state.replacementApplied, announce)
end

function UI:ToggleMap()
    self:ToggleReplacementMode(false)
end

function UI:CreateMapFrame()
    mapFrame = CreateFrame("Frame", "MapaEnMiniaturaFrame", UIParent, "BackdropTemplate")
    mapFrame:SetSize(Addon.db.size, Addon.db.size)
    mapFrame:SetFrameStrata("LOW")
    mapFrame:SetToplevel(true)
    mapFrame:SetClampedToScreen(true)
    mapFrame:SetMovable(true)
    mapFrame:SetAlpha(Addon.db.alpha)
    mapFrame:SetBackdrop({
        bgFile = "Interface\\Buttons\\WHITE8X8",
        edgeFile = "Interface\\Buttons\\WHITE8X8",
        edgeSize = 5,
        insets = { left = 4, right = 4, top = 4, bottom = 4 },
    })
    mapFrame:SetBackdropColor(0.02, 0.02, 0.03, 0.96)
    mapFrame:Hide()
    RestoreFramePosition()

    if MinimapCluster then
        MinimapCluster:HookScript("OnShow", function(self)
            if Addon.db and state.replacementApplied then
                self:Hide()
            end
        end)
    end
    if Minimap then
        Minimap:HookScript("OnShow", function(self)
            local gatheringViewActive = Addon.Gathering and Addon.Gathering:IsActive()
            if Addon.db and state.replacementApplied and not gatheringViewActive then
                self:Hide()
            end
        end)
    end

    titleBar = CreateFrame("Frame", nil, mapFrame)
    titleBar:SetPoint("TOPLEFT", 7, -4)
    titleBar:SetPoint("TOPRIGHT", -7, -4)
    titleBar:SetHeight(18)
    titleBar:EnableMouse(true)
    titleBar:RegisterForDrag("LeftButton")
    titleBar:SetScript("OnDragStart", function()
        if not Addon.db.locked then
            mapFrame:StartMoving()
        end
    end)
    titleBar:SetScript("OnDragStop", function()
        mapFrame:StopMovingOrSizing()
        SaveFramePosition()
    end)

    titleText = titleBar:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    titleText:SetPoint("LEFT", 4, 0)
    titleText:SetPoint("RIGHT", -116, 0)
    titleText:SetJustifyH("LEFT")
    titleText:SetText(L.APP_NAME)

    closeButton = CreateFrame("Button", nil, mapFrame, "UIPanelCloseButton")
    closeButton:SetSize(20, 20)
    closeButton:SetPoint("TOPRIGHT", 1, 1)
    closeButton:SetScript("OnClick", function()
        self:ToggleMap()
    end)

    plusButton = MakeHeaderButton(titleBar, "+", 22, function()
        Addon.MapView:ChangeZoom(1)
    end)
    plusButton:SetPoint("RIGHT", 0, 0)

    minusButton = MakeHeaderButton(titleBar, "-", 22, function()
        Addon.MapView:ChangeZoom(-1)
    end)
    minusButton:SetPoint("RIGHT", plusButton, "LEFT", -2, 0)

    centerButton = MakeHeaderButton(titleBar, "C", 22, function()
        Addon.MapView:Recenter()
    end)
    centerButton:SetPoint("RIGHT", minusButton, "LEFT", -2, 0)
    centerButton:SetScript("OnEnter", function(button)
        GameTooltip:SetOwner(button, "ANCHOR_BOTTOM")
        GameTooltip:SetText(L.CENTER_ON_PLAYER)
        GameTooltip:Show()
    end)
    centerButton:SetScript("OnLeave", GameTooltip_Hide)

    viewport = CreateFrame("Frame", nil, mapFrame, "BackdropTemplate")
    viewport:SetPoint("TOPLEFT", 9, -32)
    viewport:SetPoint("BOTTOMRIGHT", -9, 27)
    viewport:SetClipsChildren(true)
    viewport:EnableMouse(true)
    viewport:EnableMouseWheel(true)
    viewport:SetBackdrop({
        bgFile = "Interface\\Buttons\\WHITE8X8",
        edgeFile = "Interface\\Buttons\\WHITE8X8",
        edgeSize = 1,
    })
    viewport:SetBackdropColor(0, 0, 0, 1)
    viewport:SetBackdropBorderColor(0.18, 0.18, 0.22, 1)

    circleBorder = mapFrame:CreateTexture(nil, "BACKGROUND", nil, 1)
    circleBorder:SetTexture(186178)
    circleBorder:SetVertexColor(0.05, 0.05, 0.06, 1)
    circleBorder:Hide()

    canvas = CreateFrame("Frame", nil, viewport)
    canvas:SetSize(1, 1)
    canvas:SetClipsChildren(true)
    canvas:SetPoint("CENTER")

    circleMask = canvas:CreateMaskTexture(nil, "BACKGROUND")
    circleMask:SetTexture(186178)
    circleMask:SetAllPoints(viewport)

    helpText = viewport:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
    helpText:SetPoint("CENTER")
    helpText:SetWidth(Addon.db.size - 50)
    helpText:SetText(L.LOADING_MAP)

    statusText = mapFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    statusText:SetPoint("BOTTOMLEFT", 10, 9)
    statusText:SetPoint("BOTTOMRIGHT", -10, 9)
    statusText:SetJustifyH("CENTER")
    statusText:SetText(L.LOADING)

    Addon.ui = {
        mapFrame = mapFrame,
        viewport = viewport,
        canvas = canvas,
        titleText = titleText,
        statusText = statusText,
        helpText = helpText,
    }
    Addon.MapView:Initialize(Addon.ui)
    Addon.Markers:Initialize(Addon.ui)
    Addon.Gathering:Initialize(Addon.ui)
    Addon.AddonButtons:Initialize(Addon.ui)
    self:ApplyAppearance()

    viewport:SetScript("OnMouseWheel", function(_, delta)
        if IsControlKeyDown() then
            local minimumSize = Addon.db.shape == "circle" and Addon.MIN_SIZE or Addon.MIN_SQUARE_SIZE
            Addon.db.size = Addon:Clamp(
                Addon.db.size + (delta > 0 and 10 or -10),
                minimumSize,
                Addon.MAX_SIZE
            )
            self:SetSize(Addon.db.size)
        else
            Addon.MapView:ChangeZoom(delta > 0 and 1 or -1)
        end
    end)
    viewport:SetScript("OnMouseDown", function(_, button)
        if button == "LeftButton" then
            if IsShiftKeyDown() and not Addon.db.locked then
                state.movingFrame = true
                mapFrame:StartMoving()
            else
                state.draggingMap = true
                state.followPlayer = false
                state.lastCursorX, state.lastCursorY = Addon:GetScaledCursorPosition()
            end
        elseif button == "RightButton" then
            Addon.MapView:Recenter()
        end
    end)
    viewport:SetScript("OnMouseUp", function(_, button)
        if button == "LeftButton" then
            state.draggingMap = false
            if state.movingFrame then
                state.movingFrame = false
                mapFrame:StopMovingOrSizing()
                SaveFramePosition()
            end
        end
    end)
    viewport:SetScript("OnHide", function()
        state.draggingMap = false
        if state.movingFrame then
            state.movingFrame = false
            mapFrame:StopMovingOrSizing()
            SaveFramePosition()
        end
    end)

    mapFrame:SetScript("OnUpdate", function(_, elapsed)
        if state.draggingMap then
            local cursorX, cursorY = Addon:GetScaledCursorPosition()
            state.panX = state.panX + (cursorX - state.lastCursorX)
            state.panY = state.panY + (cursorY - state.lastCursorY)
            state.lastCursorX = cursorX
            state.lastCursorY = cursorY
            Addon.MapView:PlaceCanvas()
        end

        state.elapsed = state.elapsed + elapsed
        if state.elapsed >= 0.10 then
            state.elapsed = 0
            Addon.Markers:UpdateMarkers()
            if state.followPlayer then
                if state.autoCenterUntil > GetTime() then
                    Addon.MapView:CalibrateProtectedCenter(false)
                end
                Addon.MapView:PlaceCanvas()
            end
        end
    end)

    mapFrame:SetScript("OnSizeChanged", function()
        C_Timer.After(0, function()
            if mapFrame:IsShown() then
                Addon.MapView:UpdateGeometry()
                Addon.AddonButtons:Layout()
            end
        end)
    end)
end

function UI:CreateMinimapButton()
    minimapButton = CreateFrame("Button", "MapaEnMiniaturaMinimapButton", UIParent)
    minimapButton:SetSize(31, 31)
    minimapButton:SetFrameStrata("LOW")
    minimapButton:SetFrameLevel(60)
    minimapButton:SetClampedToScreen(true)
    minimapButton:SetMovable(true)
    minimapButton:RegisterForClicks("LeftButtonUp", "RightButtonUp")
    minimapButton:RegisterForDrag("LeftButton")

    local background = minimapButton:CreateTexture(nil, "BACKGROUND")
    background:SetSize(24, 24)
    background:SetPoint("CENTER")
    background:SetTexture("Interface\\Minimap\\UI-Minimap-Background")

    local icon = minimapButton:CreateTexture(nil, "ARTWORK")
    icon:SetPoint("CENTER")
    icon:SetSize(18, 18)
    icon:SetTexture("Interface\\Icons\\INV_Misc_Map_01")
    icon:SetTexCoord(0.08, 0.92, 0.08, 0.92)
    minimapButton.icon = icon

    local border = minimapButton:CreateTexture(nil, "OVERLAY")
    border:SetSize(50, 50)
    border:SetPoint("TOPLEFT")
    border:SetTexture("Interface\\Minimap\\MiniMap-TrackingBorder")

    minimapButton:SetHighlightTexture("Interface\\Minimap\\UI-Minimap-ZoomButton-Highlight", "ADD")
    minimapButton:SetScript("OnDragStart", function(button)
        if state.replacementApplied or Addon.db.locked then
            return
        end
        button.isDragging = true
        button:StartMoving()
    end)
    minimapButton:SetScript("OnDragStop", function(button)
        if not button.isDragging then
            return
        end
        button.isDragging = false
        button:StopMovingOrSizing()
        SaveMinimapButtonPosition()
        PositionMapModeButton()
        button.suppressClick = true
        C_Timer.After(0, function()
            button.suppressClick = false
        end)
    end)
    minimapButton:SetScript("OnClick", function(clickedButton, button)
        if clickedButton.suppressClick then
            return
        end
        if button == "RightButton" then
            if not state.replacementApplied then
                self:ToggleReplacementMode(false)
            end
            C_Timer.After(0, function()
                Addon.MapView:Recenter()
            end)
        else
            self:ToggleReplacementMode(true)
        end
    end)
    minimapButton:SetScript("OnEnter", function(button)
        GameTooltip:SetOwner(button, "ANCHOR_LEFT")
        if state.replacementApplied then
            GameTooltip:SetText(L.USE_ORIGINAL_MINIMAP)
            GameTooltip:AddLine(L.CLICK_RETURN_BLIZZARD, 1, 1, 1)
        else
            GameTooltip:SetText(L.USE_MIYAMAP)
            GameTooltip:AddLine(L.CLICK_USE_MIYAMAP, 1, 1, 1)
        end
        GameTooltip:AddLine(L.RIGHT_CLICK_OPEN_CENTER, 0.65, 0.82, 1)
        GameTooltip:Show()
    end)
    minimapButton:SetScript("OnLeave", GameTooltip_Hide)
    PositionMapModeButton()
end

function UI:RegisterAddonCompartmentEntry()
    if not AddonCompartmentFrame then
        return
    end

    AddonCompartmentFrame:RegisterAddon({
        text = L.APP_NAME,
        icon = "Interface\\Icons\\INV_Misc_Map_01",
        notCheckable = true,
        func = function()
            self:ToggleMap()
        end,
        funcOnEnter = function(button)
            GameTooltip:SetOwner(button, "ANCHOR_LEFT")
            GameTooltip:SetText(L.APP_NAME)
            GameTooltip:AddLine(L.SHOW_HIDE_ZONE_MAP, 1, 1, 1)
            GameTooltip:Show()
        end,
        funcOnLeave = GameTooltip_Hide,
    })
end

function UI:ApplyAppearance()
    local circular = Addon.db.shape == "circle"
    local borderSize = Addon.db.borderSize

    mapFrame:SetBackdrop({
        bgFile = "Interface\\Buttons\\WHITE8X8",
        edgeFile = "Interface\\Buttons\\WHITE8X8",
        edgeSize = math.max(borderSize, 1),
        insets = {
            left = borderSize,
            right = borderSize,
            top = borderSize,
            bottom = borderSize,
        },
    })

    viewport:ClearAllPoints()
    if circular then
        titleBar:Hide()
        closeButton:Hide()
        statusText:Hide()
        viewport:SetPoint("TOPLEFT", mapFrame, "TOPLEFT", borderSize, -borderSize)
        viewport:SetPoint("BOTTOMRIGHT", mapFrame, "BOTTOMRIGHT", -borderSize, borderSize)
        viewport:SetBackdropColor(0, 0, 0, 0)
        viewport:SetBackdropBorderColor(0, 0, 0, 0)
        mapFrame:SetBackdropColor(0, 0, 0, 0)
        mapFrame:SetBackdropBorderColor(0, 0, 0, 0)

        circleBorder:ClearAllPoints()
        circleBorder:SetPoint("TOPLEFT", viewport, "TOPLEFT", -borderSize, borderSize)
        circleBorder:SetPoint("BOTTOMRIGHT", viewport, "BOTTOMRIGHT", borderSize, -borderSize)
        circleBorder:Show()
        Addon.MapView:SetShapeMask(circleMask)
    else
        titleBar:Hide()
        closeButton:Hide()
        statusText:Hide()

        local sideInset = math.max(borderSize, 1)
        viewport:SetPoint("TOPLEFT", mapFrame, "TOPLEFT", sideInset, -sideInset)
        viewport:SetPoint("BOTTOMRIGHT", mapFrame, "BOTTOMRIGHT", -sideInset, sideInset)
        viewport:SetBackdropColor(0, 0, 0, 1)
        viewport:SetBackdropBorderColor(0.18, 0.18, 0.22, 1)
        mapFrame:SetBackdropColor(0.02, 0.02, 0.03, 0.96)
        if borderSize > 0 then
            mapFrame:SetBackdropBorderColor(0.20, 0.20, 0.24, 1)
        else
            mapFrame:SetBackdropBorderColor(0, 0, 0, 0)
        end
        circleBorder:Hide()
        Addon.MapView:SetShapeMask(nil)
    end

    helpText:SetWidth(math.max(Addon.db.size - 40, 80))
    Addon.Markers:UpdateShapeClipping()
    Addon.AddonButtons:Layout()
end

function UI:SetShape(shape)
    Addon.db.shape = shape == "circle" and "circle" or "square"
    local minimumSize = Addon.db.shape == "circle" and Addon.MIN_SIZE or Addon.MIN_SQUARE_SIZE
    if Addon.db.size < minimumSize then
        Addon.db.size = minimumSize
        mapFrame:SetSize(minimumSize, minimumSize)
    end
    self:ApplyAppearance()
    Addon.MapView:UpdateGeometry()
end

function UI:SetBorderSize(size)
    Addon.db.borderSize = Addon:Clamp(size, Addon.MIN_BORDER_SIZE, Addon.MAX_BORDER_SIZE)
    self:ApplyAppearance()
    Addon.MapView:UpdateGeometry()
end

function UI:SetAddonButtonsShown(shown)
    Addon.db.showAddonButtons = not not shown
    Addon.AddonButtons:SetHubShown(Addon.db.showAddonButtons)
end

function UI:ApplyProfile(profile)
    if profile == "mini" then
        Addon.db.shape = "circle"
        Addon.db.size = 140
        Addon.db.borderSize = 3
        Addon.db.addonButtonSize = 22
    elseif profile == "compacto" or profile == "compact" then
        Addon.db.shape = "circle"
        Addon.db.size = 180
        Addon.db.borderSize = 5
        Addon.db.addonButtonSize = 25
    elseif profile == "normal" then
        Addon.db.shape = "square"
        Addon.db.size = 320
        Addon.db.borderSize = 5
        Addon.db.addonButtonSize = 28
    else
        return false
    end

    self:SetSize(Addon.db.size)
    self:ApplyAppearance()
    Addon.MapView:UpdateGeometry()
    Addon.AddonButtons:Layout()
    return true
end

function UI:ApplySettings()
    mapFrame:SetSize(Addon.db.size, Addon.db.size)
    mapFrame:SetAlpha(Addon.db.alpha)
    minimapButton:SetShown(Addon.db.showButton)
    RestoreFramePosition()
    self:ApplyAppearance()
    Addon.MapView:UpdateGeometry()
    Addon.Markers:SetPlayerArrowSize(Addon.db.playerArrowSize)
    Addon.Markers:RefreshContentMarkers()
    Addon.AddonButtons:UpdateBossButton()
    Addon.AddonButtons:UpdateAddsButton()
    Addon.AddonButtons:UpdateRouteButton()
    Addon.AddonButtons:UpdateGatheringButton()
    Addon.AddonButtons:UpdateServicesButton()
    self:ApplyReplacementMode(Addon.db.replaceMinimap, false)
end

function UI:ResetSettings()
    for key in pairs(Addon.db) do
        Addon.db[key] = nil
    end
    for key, value in pairs(Addon.defaults) do
        Addon.db[key] = value
    end
    Addon.db.zoomByMap = {}
    Addon.db.welcomeShown = true
    state.panX = 0
    state.panY = 0
    state.followPlayer = true
    state.movingFrame = false
    Addon.AddonButtons:ResetAnchor(false)
    self:ApplySettings()
    Addon:Print(L.SETTINGS_RESET)
end

function UI:SetSize(size)
    mapFrame:SetSize(size, size)
    helpText:SetWidth(math.max(size - 40, 80))
    Addon.AddonButtons:Layout()
end

function UI:SetAlpha(alpha)
    mapFrame:SetAlpha(alpha)
end

function UI:SetMinimapButtonShown(shown)
    minimapButton:SetShown(shown)
end

function UI:ResetMinimapButtonPosition()
    Addon.db.minimapButtonPosition = nil
    PositionMapModeButton()
end

function UI:IsMapShown()
    return mapFrame and mapFrame:IsShown()
end

function UI:Initialize()
    self:CreateMapFrame()
    self:CreateMinimapButton()
    self:RegisterAddonCompartmentEntry()
    self:RegisterDungeonChoiceDialog()
end
