local addonName, Addon = ...

Addon.name = addonName
Addon.PREFIX = "|cff33ccffMiyamap:|r "
Addon.MIN_SIZE = 120
Addon.MIN_SQUARE_SIZE = 220
Addon.MAX_SIZE = 650
Addon.MIN_ALPHA = 0.35
Addon.MAX_ALPHA = 1
Addon.MIN_ARROW_SIZE = 8
Addon.MAX_ARROW_SIZE = 40
Addon.MIN_ADDON_BUTTON_SIZE = 18
Addon.MAX_ADDON_BUTTON_SIZE = 48
Addon.MIN_BORDER_SIZE = 0
Addon.MAX_BORDER_SIZE = 16
Addon.MIN_BUTTON_DISTANCE = 0
Addon.MAX_BUTTON_DISTANCE = 30
Addon.MIN_HUB_COLUMNS = 1
Addon.MAX_HUB_COLUMNS = 8
Addon.ZOOM_LEVELS = { 1, 1.35, 1.8, 2.5, 3.5, 5 }

Addon.defaults = {
    size = 320,
    alpha = 0.95,
    playerArrowSize = 18,
    shape = "square",
    borderSize = 5,
    showAddonButtons = true,
    showBosses = true,
    showAdds = true,
    showRoute = true,
    gatheringNativeView = false,
    gatheringWarningAccepted = false,
    showNativeServices = true,
    addonButtonSize = 28,
    addonButtonDistance = 5,
    addonHubColumns = 4,
    addonHubMoved = false,
    point = "TOPRIGHT",
    relativePoint = "TOPRIGHT",
    x = -40,
    y = -220,
    zoom = 2,
    locked = false,
    showButton = true,
    replaceMinimap = true,
    lastDungeonMapChoice = "miyamap",
    dungeonMapChoicePrompted = false,
    replacementInitialized = false,
    relativeFrame = "UIParent",
    welcomeShown = false,
}

Addon.state = {
    mapID = nil,
    layer = nil,
    textureIDs = nil,
    scale = 1,
    focusX = 0.5,
    focusY = 0.5,
    panX = 0,
    panY = 0,
    followPlayer = true,
    draggingMap = false,
    movingFrame = false,
    lastCursorX = 0,
    lastCursorY = 0,
    elapsed = 0,
    contentRefreshPending = false,
    replacementApplied = false,
    autoCenterUntil = 0,
    protectedCenterMode = nil,
    protectedCenterError = nil,
    lastProtectedHintMapID = nil,
    dungeonChoiceActive = false,
    dungeonMapChoice = nil,
    dungeonInstanceID = nil,
    dungeonChoiceGeneration = 0,
}

function Addon:Print(message)
    DEFAULT_CHAT_FRAME:AddMessage(self.PREFIX .. message)
end

function Addon:Clamp(value, minimum, maximum)
    return math.max(minimum, math.min(maximum, value))
end

function Addon:IsSecret(value)
    return issecretvalue and issecretvalue(value)
end

function Addon:IsValidMapCoordinate(x, y)
    return not self:IsSecret(x)
        and not self:IsSecret(y)
        and type(x) == "number"
        and type(y) == "number"
        and x >= 0
        and x <= 1
        and y >= 0
        and y <= 1
end

function Addon:InitializeDatabase()
    MapaEnMiniaturaDB = MapaEnMiniaturaDB or {}
    self.db = MapaEnMiniaturaDB
    for key, value in pairs(self.defaults) do
        if self.db[key] == nil then
            self.db[key] = value
        end
    end

    -- Versions 0.9.2 and 0.9.3 could save player focus against MDT's custom
    -- canvas. Those values are not valid on Blizzard's map and must not be reused.
    local coordinateDataVersion = tonumber(self.db.coordinateDataVersion) or 0
    if coordinateDataVersion < 2 then
        local maps = self.DungeonEnemyData and self.DungeonEnemyData.maps
        if type(maps) == "table" and type(self.db.protectedFocusByMap) == "table" then
            for mapID in pairs(maps) do
                self.db.protectedFocusByMap[mapID] = nil
            end
        end
        self.db.coordinateDataVersion = 2
    end

    if self.db.shape ~= "circle" then
        self.db.shape = "square"
    end
    local minimumSize = self.db.shape == "circle" and self.MIN_SIZE or self.MIN_SQUARE_SIZE
    self.db.size = self:Clamp(tonumber(self.db.size) or self.defaults.size, minimumSize, self.MAX_SIZE)
    self.db.alpha = self:Clamp(tonumber(self.db.alpha) or self.defaults.alpha, self.MIN_ALPHA, self.MAX_ALPHA)
    self.db.playerArrowSize = self:Clamp(
        math.floor((tonumber(self.db.playerArrowSize) or self.defaults.playerArrowSize) + 0.5),
        self.MIN_ARROW_SIZE,
        self.MAX_ARROW_SIZE
    )
    self.db.borderSize = self:Clamp(
        math.floor((tonumber(self.db.borderSize) or self.defaults.borderSize) + 0.5),
        self.MIN_BORDER_SIZE,
        self.MAX_BORDER_SIZE
    )
    self.db.addonButtonSize = self:Clamp(
        math.floor((tonumber(self.db.addonButtonSize) or self.defaults.addonButtonSize) + 0.5),
        self.MIN_ADDON_BUTTON_SIZE,
        self.MAX_ADDON_BUTTON_SIZE
    )
    self.db.addonButtonDistance = self:Clamp(
        math.floor((tonumber(self.db.addonButtonDistance) or self.defaults.addonButtonDistance) + 0.5),
        self.MIN_BUTTON_DISTANCE,
        self.MAX_BUTTON_DISTANCE
    )
    self.db.addonHubColumns = self:Clamp(
        math.floor((tonumber(self.db.addonHubColumns) or self.defaults.addonHubColumns) + 0.5),
        self.MIN_HUB_COLUMNS,
        self.MAX_HUB_COLUMNS
    )
    self.db.showAddonButtons = self.db.showAddonButtons ~= false
    self.db.showBosses = self.db.showBosses ~= false
    self.db.showAdds = self.db.showAdds ~= false
    self.db.showRoute = self.db.showRoute ~= false
    self.db.gatheringWarningAccepted = self.db.gatheringWarningAccepted == true
    self.db.gatheringNativeView = self.db.gatheringWarningAccepted
        and self.db.gatheringNativeView == true
    self.db.showNativeServices = self.db.showNativeServices ~= false
    self.db.showGatheringRadar = nil
    self.db.showGatheringNodes = nil
    self.db.gatheringNodes = nil
    if type(self.db.gatheringMapPosition) ~= "table" then
        self.db.gatheringMapPosition = nil
    end
    local savedMinimapButtonPosition = self.db.minimapButtonPosition
    local savedMinimapButtonX = type(savedMinimapButtonPosition) == "table"
        and tonumber(savedMinimapButtonPosition.x)
    local savedMinimapButtonY = type(savedMinimapButtonPosition) == "table"
        and tonumber(savedMinimapButtonPosition.y)
    if not savedMinimapButtonX or not savedMinimapButtonY then
        self.db.minimapButtonPosition = nil
    else
        self.db.minimapButtonPosition.x = savedMinimapButtonX
        self.db.minimapButtonPosition.y = savedMinimapButtonY
    end
    self.db.replaceMinimap = self.db.replaceMinimap ~= false
    if self.db.lastDungeonMapChoice ~= "minimap" then
        self.db.lastDungeonMapChoice = "miyamap"
    end
    self.db.dungeonMapChoicePrompted = self.db.dungeonMapChoicePrompted == true
    -- Limpia los datos de la antigua importación de rutas. Los enemigos usan
    -- ahora la base compacta incluida en el addon.
    self.db.mdtRouteString = nil
    self.db.mdtRouteVisible = nil
    self.db.zoom = self:Clamp(
        math.floor(tonumber(self.db.zoom) or self.defaults.zoom),
        1,
        #self.ZOOM_LEVELS
    )
    if type(self.db.zoomByMap) ~= "table" then
        self.db.zoomByMap = {}
    end
    if type(self.db.protectedFocusByMap) ~= "table" then
        self.db.protectedFocusByMap = {}
    end
end

function Addon:GetScaledCursorPosition()
    local x, y = GetCursorPosition()
    local scale = UIParent:GetEffectiveScale()
    return x / scale, y / scale
end
