--------------------------------------------------------------------------------
-- Nanami-UI: Minimap Skin (Minimap.lua)
-- Custom cat-paw pixel art frame for the minimap
--------------------------------------------------------------------------------

SFrames.Minimap = SFrames.Minimap or {}
local MM = SFrames.Minimap
local _A = SFrames.ActiveTheme

local MAP_STYLES = {
    { key = "map", tex = "Interface\\AddOns\\Nanami-UI\\img\\map", label = "猫爪",   plateY = -10, textColor = {0.45, 0.32, 0.20} },
    { key = "zs",  tex = "Interface\\AddOns\\Nanami-UI\\img\\zs",  label = "战士",   plateY = -6,  textColor = {1, 1, 1} },
    { key = "qs",  tex = "Interface\\AddOns\\Nanami-UI\\img\\qs",  label = "圣骑士", plateY = -6,  textColor = {0.22, 0.13, 0.07} },
    { key = "lr",  tex = "Interface\\AddOns\\Nanami-UI\\img\\lr",  label = "猎人",   plateY = -6,  textColor = {1, 1, 1} },
    { key = "qxz", tex = "Interface\\AddOns\\Nanami-UI\\img\\qxz", label = "潜行者", plateY = -6,  textColor = {1, 1, 1} },
    { key = "ms",  tex = "Interface\\AddOns\\Nanami-UI\\img\\ms",  label = "牧师",   plateY = -6,  textColor = {0.22, 0.13, 0.07} },
    { key = "sm",  tex = "Interface\\AddOns\\Nanami-UI\\img\\sm",  label = "萨满",   plateY = -6,  textColor = {1, 1, 1} },
    { key = "fs",  tex = "Interface\\AddOns\\Nanami-UI\\img\\fs",  label = "法师",   plateY = -6,  textColor = {1, 1, 1} },
    { key = "ss",  tex = "Interface\\AddOns\\Nanami-UI\\img\\ss",  label = "术士",   plateY = -6,  textColor = {1, 1, 1} },
    { key = "dly", tex = "Interface\\AddOns\\Nanami-UI\\img\\dly", label = "德鲁伊", plateY = -6,  textColor = {0.22, 0.13, 0.07} },
}
local SQUARE_STYLES = {
    {
        key = "square1",
        label = "方形·金",
        tex = "Interface\\AddOns\\Nanami-UI\\img\\map_f_1",
        texSize = 512,
        mapX = 9, mapY = 9, mapW = 486, mapH = 486,
        zoneOverlay = true,
        textColor = {0.85, 0.75, 0.55},
    },
    {
        key = "square2",
        label = "方形·暗",
        tex = "Interface\\AddOns\\Nanami-UI\\img\\map_f_2",
        texSize = 512,
        mapX = 52, mapY = 61, mapW = 418, mapH = 418,
        zonePlateX = 104, zonePlateY = 18, zonePlateW = 302, zonePlateH = 45,
        textColor = {0.8, 0.8, 0.8},
    },
}
local SQUARE_MASK = "Interface\\BUTTONS\\WHITE8X8"

local TEX_SIZE   = 512
local CIRCLE_CX  = 256
local CIRCLE_CY  = 256
local CIRCLE_R   = 210
local PLATE_X    = 103
local PLATE_Y    = 29
local PLATE_W    = 200
local PLATE_H    = 66
local BASE_SIZE  = 180

local CLASS_STYLE_MAP = {
    ["Warrior"]  = "zs",  ["WARRIOR"]  = "zs",  ["战士"]     = "zs",
    ["Paladin"]  = "qs",  ["PALADIN"]  = "qs",  ["圣骑士"]   = "qs",
    ["Hunter"]   = "lr",  ["HUNTER"]   = "lr",  ["猎人"]     = "lr",
    ["Rogue"]    = "qxz", ["ROGUE"]    = "qxz", ["潜行者"]   = "qxz",
    ["Priest"]   = "ms",  ["PRIEST"]   = "ms",  ["牧师"]     = "ms",
    ["Shaman"]   = "sm",  ["SHAMAN"]   = "sm",  ["萨满祭司"] = "sm",
    ["Mage"]     = "fs",  ["MAGE"]     = "fs",  ["法师"]     = "fs",
    ["Warlock"]  = "ss",  ["WARLOCK"]  = "ss",  ["术士"]     = "ss",
    ["Druid"]    = "dly", ["DRUID"]    = "dly", ["德鲁伊"]   = "dly",
}

local DEFAULTS = {
    enabled    = true,
    scale      = 1.0,
    showClock  = true,
    showCoords = true,
    mapStyle   = "auto",
    mapShape   = "square1",
    posX       = -5,
    posY       = -5,
    mailIconX  = nil,
    mailIconY  = nil,
}

local container, overlayFrame, overlayTex
local zoneFs, clockFs, clockBg, coordFs, zoneBg
local built = false

--------------------------------------------------------------------------------
-- Helpers
--------------------------------------------------------------------------------
local function GetDB()
    if not SFramesDB then SFramesDB = {} end
    if type(SFramesDB.Minimap) ~= "table" then SFramesDB.Minimap = {} end
    local db = SFramesDB.Minimap
    for k, v in pairs(DEFAULTS) do
        if db[k] == nil then db[k] = v end
    end
    return db
end

local function ResolveStyleKey()
    local key = GetDB().mapStyle or "auto"
    if key == "auto" then
        local localName, engName = UnitClass("player")
        key = CLASS_STYLE_MAP[engName]
           or CLASS_STYLE_MAP[localName]
           or "map"
    end
    return key
end

local function GetCurrentStyle()
    local key = ResolveStyleKey()
    for _, s in ipairs(MAP_STYLES) do
        if s.key == key then return s end
    end
    return MAP_STYLES[1]
end

local function GetMapTexture()
    return GetCurrentStyle().tex
end

local function IsSquareShape()
    local shape = GetDB().mapShape or "square1"
    return shape == "square1" or shape == "square2"
end

local function GetSquareStyle()
    local shape = GetDB().mapShape or "square1"
    for _, s in ipairs(SQUARE_STYLES) do
        if s.key == shape then return s end
    end
    return SQUARE_STYLES[1]
end

local function S(texPx, frameSize)
    return texPx / TEX_SIZE * frameSize
end

local function FrameSize()
    return math.floor(BASE_SIZE * ((GetDB().scale) or 1))
end

local function ApplyPosition()
    if not container then return end
    local pos = SFramesDB and SFramesDB.Positions and SFramesDB.Positions["Minimap"]
    if pos and pos.point and pos.relativePoint then
        container:ClearAllPoints()
        container:SetPoint(pos.point, UIParent, pos.relativePoint, pos.xOfs or 0, pos.yOfs or 0)
    else
        local db = GetDB()
        local x = tonumber(db.posX) or -5
        local y = tonumber(db.posY) or -5
        container:ClearAllPoints()
        container:SetPoint("TOPRIGHT", UIParent, "TOPRIGHT", x, y)
    end
end

--------------------------------------------------------------------------------
-- Hide default Blizzard minimap chrome
-- MUST be called AFTER BuildFrame (Minimap is already reparented)
--------------------------------------------------------------------------------
local function HideDefaultElements()
    local kill = {
        MinimapBorder,
        MinimapBorderTop,
        MinimapZoomIn,
        MinimapZoomOut,
        MinimapToggleButton,
        MiniMapWorldMapButton,
        GameTimeFrame,
        MinimapZoneTextButton,
        MiniMapTracking,
        MinimapBackdrop,
    }
    for _, f in ipairs(kill) do
        if f then
            f:Hide()
            f.Show = function() end
        end
    end

    -- Hide all tracking-related frames (Turtle WoW dual tracking, etc.)
    local trackNames = {
        "MiniMapTrackingButton", "MiniMapTrackingFrame",
        "MiniMapTrackingIcon", "MiniMapTracking1", "MiniMapTracking2",
    }
    for _, name in ipairs(trackNames) do
        local f = _G[name]
        if f and f.Hide then
            f:Hide()
            f.Show = function() end
        end
    end

    -- Also hide any tracking textures that are children of Minimap
    if Minimap.GetChildren then
        local children = { Minimap:GetChildren() }
        for _, child in ipairs(children) do
            local n = child.GetName and child:GetName()
            if n and string.find(n, "Track") then
                child:Hide()
                child.Show = function() end
            end
        end
    end

    -- Move MinimapCluster off-screen instead of Hide()
    -- Hide() would cascade-hide children that were still parented at load time
    if MinimapCluster then
        MinimapCluster:ClearAllPoints()
        MinimapCluster:SetPoint("TOP", UIParent, "BOTTOM", 0, -500)
        MinimapCluster:SetWidth(1)
        MinimapCluster:SetHeight(1)
        MinimapCluster:EnableMouse(false)
    end
end

--------------------------------------------------------------------------------
-- Build
--------------------------------------------------------------------------------
local function BuildFrame()
    if built then return end
    built = true

    local fs = FrameSize()
    local isSquare = IsSquareShape()

    -- Main container
    container = CreateFrame("Frame", "SFramesMinimapContainer", UIParent)
    container:SetWidth(fs)
    container:SetHeight(fs)
    container:SetFrameStrata("LOW")
    container:SetFrameLevel(1)
    container:EnableMouse(false)
    container:SetClampedToScreen(true)

    -- Reparent the actual minimap into our container
    Minimap:SetParent(container)
    Minimap:ClearAllPoints()
    if isSquare then
        local sq = GetSquareStyle()
        local mapW = sq.mapW / sq.texSize * fs
        local mapH = sq.mapH / sq.texSize * fs
        local cx = (sq.mapX + sq.mapW / 2) / sq.texSize * fs
        local cy = (sq.mapY + sq.mapH / 2) / sq.texSize * fs
        Minimap:SetPoint("CENTER", container, "TOPLEFT", cx, -cy)
        Minimap:SetWidth(mapW)
        Minimap:SetHeight(mapH)
    else
        local mapDiam = math.floor(S((CIRCLE_R + 8) * 2, fs))
        Minimap:SetPoint("CENTER", container, "TOPLEFT",
            S(CIRCLE_CX, fs), -S(CIRCLE_CY, fs))
        Minimap:SetWidth(mapDiam)
        Minimap:SetHeight(mapDiam)
    end
    Minimap:SetFrameStrata("LOW")
    Minimap:SetFrameLevel(2)
    Minimap:Show()

    if Minimap.SetMaskTexture then
        if isSquare then
            Minimap:SetMaskTexture(SQUARE_MASK)
        else
            Minimap:SetMaskTexture("Textures\\MinimapMask")
        end
    end

    -- Decorative overlay (frame texture)
    overlayFrame = CreateFrame("Frame", nil, container)
    overlayFrame:SetAllPoints(container)
    overlayFrame:SetFrameStrata("LOW")
    overlayFrame:SetFrameLevel(Minimap:GetFrameLevel() + 3)
    overlayFrame:EnableMouse(false)

    overlayTex = overlayFrame:CreateTexture(nil, "ARTWORK")
    if isSquare then
        overlayTex:SetTexture(GetSquareStyle().tex)
    else
        overlayTex:SetTexture(GetMapTexture())
    end
    overlayTex:SetAllPoints(overlayFrame)

    -- Zone name background (semi-transparent strip for square styles)
    zoneBg = CreateFrame("Frame", nil, overlayFrame)
    zoneBg:SetFrameLevel(overlayFrame:GetFrameLevel() - 1)
    zoneBg:SetBackdrop({
        bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
    })
    zoneBg:SetBackdropColor(0, 0, 0, 0.5)
    zoneBg:Hide()

    -- Zone name
    zoneFs = overlayFrame:CreateFontString(nil, "OVERLAY")
    zoneFs:SetJustifyH("CENTER")
    zoneFs:SetJustifyV("MIDDLE")

    if isSquare then
        local sq = GetSquareStyle()
        zoneFs:SetFont(SFrames:GetFont(), 11, "OUTLINE")
        if sq.zonePlateX then
            local px = (sq.zonePlateX + sq.zonePlateW / 2) / sq.texSize * fs
            local py = (sq.zonePlateY + sq.zonePlateH / 2) / sq.texSize * fs
            zoneFs:SetPoint("CENTER", container, "TOPLEFT", px, -py)
            zoneFs:SetWidth(sq.zonePlateW / sq.texSize * fs)
            zoneFs:SetHeight(sq.zonePlateH / sq.texSize * fs)
        else
            zoneFs:SetPoint("TOP", Minimap, "TOP", 0, -3)
            zoneFs:SetWidth(Minimap:GetWidth() * 0.7)
            zoneFs:SetHeight(18)
            zoneBg:ClearAllPoints()
            zoneBg:SetPoint("TOP", Minimap, "TOP", 0, 0)
            zoneBg:SetWidth(Minimap:GetWidth())
            zoneBg:SetHeight(20)
            zoneBg:Show()
        end
        local tc = sq.textColor or {1, 1, 1}
        zoneFs:SetTextColor(tc[1], tc[2], tc[3])
    else
        local style = GetCurrentStyle()
        zoneFs:SetFont(SFrames:GetFont(), 11, "")
        local pcy = S(PLATE_Y + PLATE_H / 2 + (style.plateY or -6), fs)
        zoneFs:SetPoint("CENTER", container, "TOP", 0, -pcy)
        zoneFs:SetWidth(S(PLATE_W + 60, fs))
        zoneFs:SetHeight(S(PLATE_H, fs))
        local tc = style.textColor or {0.22, 0.13, 0.07}
        zoneFs:SetTextColor(tc[1], tc[2], tc[3])
    end

    -- Clock background (semi-transparent rounded)
    clockBg = CreateFrame("Frame", nil, overlayFrame)
    clockBg:SetFrameLevel(overlayFrame:GetFrameLevel() + 1)
    clockBg:SetBackdrop({
        bgFile   = "Interface\\Tooltips\\UI-Tooltip-Background",
        edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
        tile     = true, tileSize = 16, edgeSize = 10,
        insets   = { left = 2, right = 2, top = 2, bottom = 2 },
    })
    local _clkBg = _A.clockBg or { 0, 0, 0, 0.55 }
    local _clkBd = _A.clockBorder or { 0, 0, 0, 0.3 }
    clockBg:SetBackdropColor(_clkBg[1], _clkBg[2], _clkBg[3], _clkBg[4])
    clockBg:SetBackdropBorderColor(_clkBd[1], _clkBd[2], _clkBd[3], _clkBd[4])
    clockBg:SetWidth(46)
    clockBg:SetHeight(18)
    if isSquare then
        clockBg:SetPoint("TOP", Minimap, "BOTTOM", 0, -2)
    else
        clockBg:SetPoint("CENTER", container, "BOTTOM", 0,
            S((TEX_SIZE - CIRCLE_CY - CIRCLE_R) / 2, fs))
    end

    -- Clock text
    clockFs = clockBg:CreateFontString(nil, "OVERLAY")
    clockFs:SetFont(SFrames:GetFont(), 10, "OUTLINE")
    clockFs:SetPoint("CENTER", clockBg, "CENTER", 0, 0)
    clockFs:SetJustifyH("CENTER")
    local _clkTxt = _A.clockText or { 0.92, 0.84, 0.72 }
    clockFs:SetTextColor(_clkTxt[1], _clkTxt[2], _clkTxt[3])

    -- Coordinates (inside map area, near bottom)
    coordFs = overlayFrame:CreateFontString(nil, "OVERLAY")
    coordFs:SetFont(SFrames:GetFont(), 9, "OUTLINE")
    coordFs:SetPoint("BOTTOM", Minimap, "BOTTOM", 0, 8)
    coordFs:SetJustifyH("CENTER")
    local _coordTxt = _A.coordText or { 0.80, 0.80, 0.80 }
    coordFs:SetTextColor(_coordTxt[1], _coordTxt[2], _coordTxt[3])

    MM.container    = container
    MM.overlayFrame = overlayFrame
end

--------------------------------------------------------------------------------
-- Interactions
--------------------------------------------------------------------------------
local function SetupScrollZoom()
    Minimap:EnableMouseWheel(true)
    Minimap:SetScript("OnMouseWheel", function()
        if arg1 > 0 then
            Minimap_ZoomIn()
        else
            Minimap_ZoomOut()
        end
    end)
end

local function SetupMouseHandler()
    Minimap:SetScript("OnMouseUp", function()
        if arg1 == "RightButton" then
            if MiniMapTrackingDropDown then
                ToggleDropDownMenu(1, nil, MiniMapTrackingDropDown, "cursor")
            end
        else
            if Minimap_OnClick then
                Minimap_OnClick(this)
            end
        end
    end)
end

MM.ApplyPosition = ApplyPosition

--------------------------------------------------------------------------------
-- Reposition child icons
--------------------------------------------------------------------------------
local function SetupMailDragging()
    if not MiniMapMailFrame then return end

    MiniMapMailFrame:SetMovable(true)
    MiniMapMailFrame:EnableMouse(true)
    MiniMapMailFrame:RegisterForDrag("LeftButton")

    MiniMapMailFrame:SetScript("OnDragStart", function()
        MiniMapMailFrame:StartMoving()
    end)

    MiniMapMailFrame:SetScript("OnDragStop", function()
        MiniMapMailFrame:StopMovingOrSizing()
        local db = GetDB()
        local cx, cy = MiniMapMailFrame:GetCenter()
        local ux, uy = UIParent:GetCenter()
        if cx and cy and ux and uy then
            db.mailIconX = cx - ux
            db.mailIconY = cy - uy
        end
    end)
end

local function RepositionIcons()
    if MiniMapMailFrame then
        local db = GetDB()
        MiniMapMailFrame:ClearAllPoints()
        if db.mailIconX and db.mailIconY then
            MiniMapMailFrame:SetPoint("CENTER", UIParent, "CENTER", db.mailIconX, db.mailIconY)
        else
            local mapDiam = Minimap:GetWidth()
            MiniMapMailFrame:SetPoint("RIGHT", Minimap, "RIGHT", 8, mapDiam * 0.12)
        end
        MiniMapMailFrame:SetFrameStrata("LOW")
        MiniMapMailFrame:SetFrameLevel((overlayFrame and overlayFrame:GetFrameLevel() or 5) + 2)
        SetupMailDragging()
    end

    if MiniMapBattlefieldFrame then
        MiniMapBattlefieldFrame:ClearAllPoints()
        MiniMapBattlefieldFrame:SetPoint("BOTTOMLEFT", Minimap, "BOTTOM", 15, -8)
        MiniMapBattlefieldFrame:SetFrameStrata("LOW")
        MiniMapBattlefieldFrame:SetFrameLevel((overlayFrame and overlayFrame:GetFrameLevel() or 5) + 2)
    end
end

--------------------------------------------------------------------------------
-- Update helpers
--------------------------------------------------------------------------------
local function UpdateZoneText()
    if not zoneFs then return end
    local text = GetMinimapZoneText and GetMinimapZoneText() or ""
    lastZoneText = text
    zoneFs:SetText(text)
end

local function SetZoneMap()
    if SetMapToCurrentZone then
        pcall(SetMapToCurrentZone)
    end
end

local clockTimer = 0
local coordTimer = 0
local zoneTimer  = 0
local lastZoneText = ""

local function OnUpdate()
    local dt = arg1 or 0
    local db = GetDB()

    -- Clock (every 1 s)
    clockTimer = clockTimer + dt
    if clockTimer >= 1 then
        clockTimer = 0
        if db.showClock and clockFs then
            local timeStr
            if date then
                timeStr = date("%H:%M")
            else
                local h, m = GetGameTime()
                timeStr = string.format("%02d:%02d", h, m)
            end
            clockFs:SetText(timeStr)
            clockFs:Show()
            if clockBg then clockBg:Show() end
        elseif clockFs then
            clockFs:Hide()
            if clockBg then clockBg:Hide() end
        end
    end

    -- Zone text (every 1 s) – catches late API updates missed by events
    zoneTimer = zoneTimer + dt
    if zoneTimer >= 1 then
        zoneTimer = 0
        if zoneFs and GetMinimapZoneText then
            local cur = GetMinimapZoneText() or ""
            if cur ~= lastZoneText then
                lastZoneText = cur
                zoneFs:SetText(cur)
            end
        end
    end

    -- Coordinates (every 0.25 s)
    coordTimer = coordTimer + dt
    if coordTimer >= 0.25 then
        coordTimer = 0
        if db.showCoords and coordFs and GetPlayerMapPosition then
            local ok, x, y = pcall(GetPlayerMapPosition, "player")
            if ok and x and y and (x > 0 or y > 0) then
                coordFs:SetText(string.format("%.1f, %.1f", x * 100, y * 100))
                coordFs:Show()
            else
                coordFs:Hide()
            end
        elseif coordFs then
            coordFs:Hide()
        end
    end
end

--------------------------------------------------------------------------------
-- Public API
--------------------------------------------------------------------------------
function MM:Refresh()
    if not container then return end

    local fs = FrameSize()
    local isSquare = IsSquareShape()

    container:SetWidth(fs)
    container:SetHeight(fs)

    -- Apply mask
    if Minimap.SetMaskTexture then
        if isSquare then
            Minimap:SetMaskTexture(SQUARE_MASK)
        else
            Minimap:SetMaskTexture("Textures\\MinimapMask")
        end
    end

    -- Position and size minimap
    Minimap:ClearAllPoints()
    if isSquare then
        local sq = GetSquareStyle()
        local mapW = sq.mapW / sq.texSize * fs
        local mapH = sq.mapH / sq.texSize * fs
        local cx = (sq.mapX + sq.mapW / 2) / sq.texSize * fs
        local cy = (sq.mapY + sq.mapH / 2) / sq.texSize * fs
        Minimap:SetPoint("CENTER", container, "TOPLEFT", cx, -cy)
        Minimap:SetWidth(mapW)
        Minimap:SetHeight(mapH)
    else
        local mapDiam = math.floor(S((CIRCLE_R + 8) * 2, fs))
        Minimap:SetPoint("CENTER", container, "TOPLEFT",
            S(CIRCLE_CX, fs), -S(CIRCLE_CY, fs))
        Minimap:SetWidth(mapDiam)
        Minimap:SetHeight(mapDiam)
    end

    -- Update overlay texture
    if overlayTex then
        if isSquare then
            overlayTex:SetTexture(GetSquareStyle().tex)
        else
            overlayTex:SetTexture(GetMapTexture())
        end
    end

    -- Update zone text
    if zoneFs then
        zoneFs:ClearAllPoints()
        if isSquare then
            local sq = GetSquareStyle()
            zoneFs:SetFont(SFrames:GetFont(), 11, "OUTLINE")
            if sq.zonePlateX then
                local px = (sq.zonePlateX + sq.zonePlateW / 2) / sq.texSize * fs
                local py = (sq.zonePlateY + sq.zonePlateH / 2) / sq.texSize * fs
                zoneFs:SetPoint("CENTER", container, "TOPLEFT", px, -py)
                zoneFs:SetWidth(sq.zonePlateW / sq.texSize * fs)
                zoneFs:SetHeight(sq.zonePlateH / sq.texSize * fs)
            else
                zoneFs:SetPoint("TOP", Minimap, "TOP", 0, -3)
                zoneFs:SetWidth(Minimap:GetWidth() * 0.7)
                zoneFs:SetHeight(18)
            end
            local tc = sq.textColor or {1, 1, 1}
            zoneFs:SetTextColor(tc[1], tc[2], tc[3])
        else
            zoneFs:SetFont(SFrames:GetFont(), 11, "")
            local style = GetCurrentStyle()
            local pcy = S(PLATE_Y + PLATE_H / 2 + (style.plateY or -6), fs)
            zoneFs:SetPoint("CENTER", container, "TOP", 0, -pcy)
            zoneFs:SetWidth(S(PLATE_W + 60, fs))
            local tc = style.textColor or {0.22, 0.13, 0.07}
            zoneFs:SetTextColor(tc[1], tc[2], tc[3])
        end
    end

    -- Zone background (semi-transparent strip, only for square styles with zoneOverlay)
    if zoneBg then
        if isSquare and GetSquareStyle().zoneOverlay then
            zoneBg:ClearAllPoints()
            zoneBg:SetPoint("TOP", Minimap, "TOP", 0, 0)
            zoneBg:SetWidth(Minimap:GetWidth())
            zoneBg:SetHeight(20)
            zoneBg:Show()
        else
            zoneBg:Hide()
        end
    end

    -- Clock
    if clockBg then
        clockBg:ClearAllPoints()
        if isSquare then
            clockBg:SetPoint("TOP", Minimap, "BOTTOM", 0, -2)
        else
            clockBg:SetPoint("CENTER", container, "BOTTOM", 0,
                S((TEX_SIZE - CIRCLE_CY - CIRCLE_R) / 2, fs))
        end
    end

    -- Coords
    if coordFs then
        coordFs:ClearAllPoints()
        coordFs:SetPoint("BOTTOM", Minimap, "BOTTOM", 0, 8)
    end

    UpdateZoneText()
    RepositionIcons()
end

MM.MAP_STYLES = MAP_STYLES
MM.SQUARE_STYLES = SQUARE_STYLES

--------------------------------------------------------------------------------
-- Shield: re-apply our skin after other addons (ShaguTweaks etc.) touch Minimap
--------------------------------------------------------------------------------
local shielded = false

local function ShieldMinimap()
    if shielded then return end
    shielded = true

    if Minimap:GetParent() ~= container then
        Minimap:SetParent(container)
    end

    local fs = FrameSize()
    local isSquare = IsSquareShape()

    Minimap:ClearAllPoints()
    if isSquare then
        local sq = GetSquareStyle()
        local mapW = sq.mapW / sq.texSize * fs
        local mapH = sq.mapH / sq.texSize * fs
        local cx = (sq.mapX + sq.mapW / 2) / sq.texSize * fs
        local cy = (sq.mapY + sq.mapH / 2) / sq.texSize * fs
        Minimap:SetPoint("CENTER", container, "TOPLEFT", cx, -cy)
        Minimap:SetWidth(mapW)
        Minimap:SetHeight(mapH)
    else
        local mapDiam = math.floor(S((CIRCLE_R + 8) * 2, fs))
        Minimap:SetPoint("CENTER", container, "TOPLEFT",
            S(CIRCLE_CX, fs), -S(CIRCLE_CY, fs))
        Minimap:SetWidth(mapDiam)
        Minimap:SetHeight(mapDiam)
    end
    Minimap:SetFrameStrata("LOW")
    Minimap:SetFrameLevel(2)
    Minimap:Show()

    if Minimap.SetMaskTexture then
        if isSquare then
            Minimap:SetMaskTexture(SQUARE_MASK)
        else
            Minimap:SetMaskTexture("Textures\\MinimapMask")
        end
    end

    HideDefaultElements()

    -- Kill any border/backdrop that ShaguTweaks may have injected
    local regions = { Minimap:GetRegions() }
    for _, r in ipairs(regions) do
        if r and r:IsObjectType("Texture") then
            local tex = r.GetTexture and r:GetTexture()
            if tex and type(tex) == "string" then
                local low = string.lower(tex)
                if string.find(low, "border") or string.find(low, "backdrop")
                   or string.find(low, "overlay") or string.find(low, "background") then
                    r:Hide()
                end
            end
        end
    end

    shielded = false
end

function MM:Initialize()
    if not Minimap then return end

    local db = GetDB()
    if db.enabled == false then return end

    local ok, err = pcall(function()
        -- Build first (reparents Minimap), THEN hide old chrome
        BuildFrame()
        HideDefaultElements()

        -- Ensure Minimap is visible after reparent
        Minimap:Show()

        SetupScrollZoom()
        SetupMouseHandler()

        -- Apply position from settings
        ApplyPosition()

        RepositionIcons()

        -- Zone text events
        SFrames:RegisterEvent("ZONE_CHANGED", function()
            SetZoneMap()
            UpdateZoneText()
        end)
        SFrames:RegisterEvent("ZONE_CHANGED_NEW_AREA", function()
            SetZoneMap()
            UpdateZoneText()
        end)
        SFrames:RegisterEvent("ZONE_CHANGED_INDOORS", function()
            SetZoneMap()
            UpdateZoneText()
        end)

        -- Re-apply after other addons finish loading (ShaguTweaks etc.)
        SFrames:RegisterEvent("PLAYER_ENTERING_WORLD", function()
            pcall(ShieldMinimap)
            pcall(UpdateZoneText)
        end)

        -- Delayed zone text: GetMinimapZoneText() may be empty at PLAYER_LOGIN
        local zoneDelay = CreateFrame("Frame")
        local elapsed = 0
        zoneDelay:SetScript("OnUpdate", function()
            elapsed = elapsed + (arg1 or 0)
            if elapsed >= 1 then
                zoneDelay:SetScript("OnUpdate", nil)
                pcall(SetZoneMap)
                pcall(UpdateZoneText)
            end
        end)

        -- Tick
        container:SetScript("OnUpdate", OnUpdate)

        -- First refresh
        SetZoneMap()
        UpdateZoneText()
        MM:Refresh()
    end)

    if not ok then
        DEFAULT_CHAT_FRAME:AddMessage("|cffff4444Nanami-UI Minimap error: " .. tostring(err) .. "|r")
    end

    if SFrames.Movers and SFrames.Movers.RegisterMover and container then
        SFrames.Movers:RegisterMover("Minimap", container, "小地图",
            "TOPRIGHT", "UIParent", "TOPRIGHT", db.posX or -5, db.posY or -5,
            function()
                pcall(RepositionIcons)
            end)
    end
end
