// ComfyUI Endless 🌊✨ Minimap - Optimized Version

(function waitForHelpers() {
    if (typeof window.EndlessHelpers === 'undefined') {
        console.warn("⏳ Waiting for EndlessHelpers to be ready...");
        setTimeout(waitForHelpers, 100);
        return;
    }

    const {
        registerEndlessTool,
        onThemeChange,
        getComfyUIColors,
        toRGBA,
        makeDraggable
    } = window.EndlessHelpers;

    console.log("✅ Endless Minimap loaded.");

    // State variables
    let currentDialog = null;
    let animationId = null;
    let unregisterThemeCallback = null;
    let resizeObserver = null;

    // Canvas state
    let panX = 0, panY = 0, zoom = 1;
    let isDragging = false;
    let dragStartTime = 0, dragStartX = 0, dragStartY = 0;
    const DRAG_THRESHOLD = 5;

    // Size constants
    const BASE_WIDTH = 300, BASE_HEIGHT = 400;
    const MAX_WIDTH = 500, MAX_HEIGHT = 600;
    const MIN_WIDTH = 200, MIN_HEIGHT = 150;

    // Node type colors - comprehensive mapping
    const NODE_COLORS = {
        // Image Processing (Blue family)
        'LoadImage': '#5DADE2', 'SaveImage': '#3498DB', 'PreviewImage': '#2E86AB',
        'ImageScale': '#85C1E9', 'ImageCrop': '#7FB3D3', 'ImageBlend': '#6BB6FF',
        
        // Latent Processing (Purple family)
        'KSampler': '#8E44AD', 'KSamplerAdvanced': '#9B59B6', 'EmptyLatentImage': '#A569BD',
        'LatentUpscale': '#BB8FCE', 'LatentBlend': '#D2B4DE',
        
        // VAE (Green family)
        'VAEDecode': '#27AE60', 'VAEEncode': '#2ECC71', 'VAELoader': '#58D68D',
        
        // Model/Checkpoint (Teal family)
        'CheckpointLoaderSimple': '#17A2B8', 'CheckpointLoader': '#148A99',
        'ModelMergeSimple': '#1ABC9C', 'UNETLoader': '#5DADE2',
        
        // CLIP/Text (Orange family)
        'CLIPTextEncode': '#E67E22', 'CLIPTextEncodeSDXL': '#F39C12',
        'CLIPLoader': '#F8C471', 'CLIPVisionEncode': '#D68910',
        
        // LoRA (Yellow family)
        'LoraLoader': '#F1C40F', 'LoraLoaderModelOnly': '#F4D03F',
        
        // ControlNet (Pink family)
        'ControlNetLoader': '#E91E63', 'ControlNetApply': '#F06292',
        'CannyEdgePreprocessor': '#EC407A', 'OpenposePreprocessor': '#F8BBD9',
        
        // Conditioning (Coral family)
        'ConditioningAverage': '#FF6B35', 'ConditioningCombine': '#FF8C42',
        
        // Utility (Gray family)
        'PrimitiveNode': '#95A5A6', 'Note': '#BDC3C7', 'Reroute': '#85929E',
        
        // Upscaling (Lime family)
        'UpscaleModelLoader': '#7FB069', 'ImageUpscaleWithModel': '#8BC34A',
        
        // Masks (Red family)
        'MaskComposite': '#E53935', 'MaskToImage': '#F44336', 'ImageToMask': '#EF5350',
        
        'default': 'rgba(200, 200, 200, 0.7)'
    };

    function getApp() {
        return window.app || window.comfyApp || document.querySelector('#app')?.__vue__?.$root || null;
    }

    function getCanvasAspectRatio() {
        const mainCanvas = document.querySelector('canvas') || 
                          document.querySelector('#graph-canvas') ||
                          document.querySelector('.litegraph');
        
        if (mainCanvas) {
            const rect = mainCanvas.getBoundingClientRect();
            return rect.width / rect.height;
        }
        
        return window.innerWidth / window.innerHeight;
    }

    function calculateDimensions() {
        const aspectRatio = getCanvasAspectRatio();
        let containerWidth, containerHeight, canvasWidth, canvasHeight;
        
        if (aspectRatio > 1) {
            containerWidth = Math.max(MIN_WIDTH, Math.min(MAX_WIDTH, BASE_WIDTH * aspectRatio));
            containerHeight = BASE_HEIGHT;
            canvasWidth = containerWidth;
            canvasHeight = BASE_HEIGHT - 50;
        } else {
            containerWidth = BASE_WIDTH;
            containerHeight = Math.max(MIN_HEIGHT, Math.min(MAX_HEIGHT, BASE_HEIGHT / aspectRatio));
            canvasWidth = containerWidth;
            canvasHeight = containerHeight - 50;
        }
        
        return { containerWidth, containerHeight, canvasWidth, canvasHeight };
    }

    function getNodeColor(node) {
        const nodeType = node.type || node.constructor?.name || 'default';
        
        if (NODE_COLORS[nodeType]) return NODE_COLORS[nodeType];
        
        // Pattern matching for common types
        const patterns = [
            ['Sampler', NODE_COLORS['KSampler']],
            ['CLIP', NODE_COLORS['CLIPTextEncode']],
            ['VAE', NODE_COLORS['VAEDecode']],
            ['ControlNet', NODE_COLORS['ControlNetLoader']],
            ['Lora', NODE_COLORS['LoraLoader']],
            ['Image.*Load', NODE_COLORS['LoadImage']],
            ['Image.*Save', NODE_COLORS['SaveImage']],
            ['Checkpoint', NODE_COLORS['CheckpointLoaderSimple']],
            ['Upscale', NODE_COLORS['UpscaleModelLoader']],
            ['Mask', NODE_COLORS['MaskComposite']]
        ];
        
        for (const [pattern, color] of patterns) {
            if (new RegExp(pattern, 'i').test(nodeType)) return color;
        }
        
        return NODE_COLORS.default;
    }

    function getNodes() {
        const app = getApp();
        if (!app) {
            console.log("App not found, trying DOM fallback...");
            const nodeElements = document.querySelectorAll('[class*="node"], .comfy-node, .litegraph-node');
            if (nodeElements.length > 0) {
                return Array.from(nodeElements).map((el, i) => ({
                    pos: [i * 150, i * 100],
                    size: [100, 60],
                    type: 'Unknown',
                    title: `Node ${i + 1}`
                }));
            }
            return null;
        }

        const nodes = app.graph?._nodes || 
                     app.graph?.nodes || 
                     app.canvas?.graph?._nodes ||
                     app.canvas?.graph?.nodes ||
                     [];
        
        return nodes;
    }

    function createStyleCSS(colors) {
        return `
            #endless-minimap button {
                background: none;
                border: none;
                color: ${colors.inputText};
                cursor: pointer;
                padding: 2px 6px;
                font-size: 18px;
                border-radius: 3px;
                transition: background 0.2s ease;
            }
            #endless-minimap button:hover {
                background: ${toRGBA(colors.inputText, 0.1)};
            }
            #endless-minimap .drag-bar {
                padding: 4px 8px;
                background: ${toRGBA(colors.inputText, 0.05)};
                cursor: move;
                font-size: 14px;
                user-select: none;
                border-bottom: 1px solid ${colors.border};
                flex-shrink: 0;
            }
            #endless-minimap .legend {
                position: absolute;
                top: 5px;
                left: 5px;
                background: ${colors.menu};
                color: ${colors.inputText};
                padding: 8px;
                border: 1px solid ${colors.border};
                border-radius: 4px;
                font-size: 10px;
                max-height: 200px;
                overflow-y: auto;
                display: none;
                z-index: 1;
            }
            #endless-minimap .pan-info {
                padding: 2px 8px;
                font-size: 10px;
                background: ${colors.menuSecondary};
                color: ${colors.inputText};
                border-top: 1px solid ${colors.border};
                text-align: center;
                flex-shrink: 0;
            }
        `;
    }

    function updateTheme() {
        if (!currentDialog) return;
        
        const colors = getComfyUIColors();
        
        // Update container colors only, not size
        currentDialog.style.background = colors.menu;
        currentDialog.style.color = colors.inputText;
        currentDialog.style.borderColor = colors.accent;
        
        // Update style tag
        const styleTag = document.getElementById('minimap-style');
        if (styleTag) {
            styleTag.textContent = createStyleCSS(colors);
        }
        
        drawMinimap();
    }

    function updateLegend() {
        const legend = currentDialog.querySelector('.legend');
        if (!legend || legend.style.display === 'none') return;
        
        const nodes = getNodes();
        if (!nodes) return;

        const typeCounts = {};
        nodes.forEach(n => {
            const nodeType = n.type || n.constructor?.name || 'default';
            typeCounts[nodeType] = (typeCounts[nodeType] || 0) + 1;
        });

        legend.innerHTML = Object.entries(typeCounts)
            .sort((a, b) => b[1] - a[1])
            .map(([type, count]) => {
                const color = NODE_COLORS[type] || NODE_COLORS.default;
                return `<div style="margin: 2px 0; display: flex; align-items: center;">
                    <div style="width: 12px; height: 12px; background: ${color}; margin-right: 6px; border-radius: 2px;"></div>
                    <span>${type} (${count})</span>
                </div>`;
            }).join('');
    }

    // Get current transform state for coordinate conversions
    function getTransformState() {
        const canvas = currentDialog?.querySelector('canvas');
        if (!canvas) return null;

        const nodes = getNodes();
        if (!nodes?.length) return null;

        // Calculate bounds (same as in drawMinimap)
        const bounds = nodes.reduce((acc, n) => {
            const x = n.pos?.[0] ?? n.x ?? 0;
            const y = n.pos?.[1] ?? n.y ?? 0;
            const w = n.size?.[0] ?? n.width ?? 100;
            const h = n.size?.[1] ?? n.height ?? 60;
            
            return {
                minX: Math.min(acc.minX, x),
                minY: Math.min(acc.minY, y),
                maxX: Math.max(acc.maxX, x + w),
                maxY: Math.max(acc.maxY, y + h)
            };
        }, { minX: Infinity, minY: Infinity, maxX: -Infinity, maxY: -Infinity });

        const width = bounds.maxX - bounds.minX;
        const height = bounds.maxY - bounds.minY;
        if (width <= 0 || height <= 0) return null;

        const baseScale = Math.min(canvas.width / Math.max(width, 1000), canvas.height / Math.max(height, 1000));
        const scale = baseScale * zoom;

        return {
            bounds,
            width,
            height,
            scale,
            canvas
        };
    }

    // Convert canvas coordinates to world coordinates
    function canvasToWorld(canvasX, canvasY) {
        const transform = getTransformState();
        if (!transform) return null;

        const { bounds, width, height, scale, canvas } = transform;

        // Inverse of the transform used in drawMinimap
        const worldX = (canvasX - canvas.width / 2 - panX) / scale + (bounds.minX + width / 2);
        const worldY = (canvasY - canvas.height / 2 - panY) / scale + (bounds.minY + height / 2);

        return { x: worldX, y: worldY };
    }

    // Convert world coordinates to canvas coordinates
    function worldToCanvas(worldX, worldY) {
        const transform = getTransformState();
        if (!transform) return null;

        const { bounds, width, height, scale, canvas } = transform;

        // Same transform as used in drawMinimap
        const canvasX = (worldX - (bounds.minX + width / 2)) * scale + canvas.width / 2 + panX;
        const canvasY = (worldY - (bounds.minY + height / 2)) * scale + canvas.height / 2 + panY;

        return { x: canvasX, y: canvasY };
    }

    function drawMinimap() {
        if (!currentDialog) return;
        
        const canvas = currentDialog.querySelector('canvas');
        const panInfo = currentDialog.querySelector('.pan-info');
        if (!canvas || !panInfo) return;
        
        const ctx = canvas.getContext('2d');
        const colors = getComfyUIColors();
        
        ctx.clearRect(0, 0, canvas.width, canvas.height);

        const nodes = getNodes();
        if (!nodes || !nodes.length) {
            ctx.fillStyle = colors.inputText;
            ctx.font = '12px Arial';
            ctx.textAlign = 'center';
            ctx.fillText('No nodes found', canvas.width / 2, canvas.height / 2);
            ctx.fillText('or graph not loaded', canvas.width / 2, canvas.height / 2 + 15);
            return;
        }

        // Calculate bounds
        const bounds = nodes.reduce((acc, n) => {
            const x = n.pos?.[0] ?? n.x ?? 0;
            const y = n.pos?.[1] ?? n.y ?? 0;
            const w = n.size?.[0] ?? n.width ?? 100;
            const h = n.size?.[1] ?? n.height ?? 60;
            
            return {
                minX: Math.min(acc.minX, x),
                minY: Math.min(acc.minY, y),
                maxX: Math.max(acc.maxX, x + w),
                maxY: Math.max(acc.maxY, y + h)
            };
        }, { minX: Infinity, minY: Infinity, maxX: -Infinity, maxY: -Infinity });

        const width = bounds.maxX - bounds.minX;
        const height = bounds.maxY - bounds.minY;
        if (width <= 0 || height <= 0) return;

        const baseScale = Math.min(canvas.width / Math.max(width, 1000), canvas.height / Math.max(height, 1000));
        const scale = baseScale * zoom;

        ctx.save();
        ctx.translate(canvas.width / 2 + panX, canvas.height / 2 + panY);
        ctx.scale(scale, scale);
        ctx.translate(-(bounds.minX + width/2), -(bounds.minY + height/2));

        // Draw grid
        ctx.strokeStyle = toRGBA(colors.inputText, 0.1);
        ctx.lineWidth = 1 / scale;
        const gridSize = 100;
        for (let x = Math.floor(bounds.minX / gridSize) * gridSize; x <= bounds.maxX; x += gridSize) {
            ctx.beginPath();
            ctx.moveTo(x, bounds.minY);
            ctx.lineTo(x, bounds.maxY);
            ctx.stroke();
        }
        for (let y = Math.floor(bounds.minY / gridSize) * gridSize; y <= bounds.maxY; y += gridSize) {
            ctx.beginPath();
            ctx.moveTo(bounds.minX, y);
            ctx.lineTo(bounds.maxX, y);
            ctx.stroke();
        }

        // Draw nodes
        nodes.forEach((n, index) => {
            const x = n.pos?.[0] ?? n.x ?? 0;
            const y = n.pos?.[1] ?? n.y ?? 0;
            const w = n.size?.[0] ?? n.width ?? 100;
            const h = n.size?.[1] ?? n.height ?? 60;
            
            ctx.fillStyle = getNodeColor(n);
            ctx.fillRect(x, y, w, h);
            
            ctx.strokeStyle = toRGBA(colors.inputText, 0.8);
            ctx.lineWidth = 1 / scale;
            ctx.strokeRect(x, y, w, h);

            if (scale > 0.3) {
                ctx.fillStyle = colors.inputText;
                ctx.font = `${Math.max(10, 12 / scale)}px Arial`;
                ctx.textAlign = 'center';
                ctx.textBaseline = 'middle';
                const title = n.title || n.type || `Node ${index + 1}`;
                ctx.fillText(title.substring(0, 15), x + w / 2, y + h / 2);
            }
        });

        // Draw viewport indicator
        const app = getApp();
        if (app?.canvas?.ds) {
            const ds = app.canvas.ds;
            const mainCanvas = document.querySelector('canvas');
            
            if (mainCanvas) {
                const viewportX = -ds.offset[0];
                const viewportY = -ds.offset[1];
                const viewportW = mainCanvas.width / ds.scale;
                const viewportH = mainCanvas.height / ds.scale;

                ctx.fillStyle = toRGBA(colors.accent || '#4a90e2', 0.12);
                ctx.fillRect(viewportX, viewportY, viewportW, viewportH);

                ctx.strokeStyle = toRGBA(colors.accent || '#4a90e2', 0.8);
                ctx.lineWidth = 2 / scale;
                ctx.strokeRect(viewportX, viewportY, viewportW, viewportH);
            }
        }

        ctx.restore();
        panInfo.textContent = `Nodes: ${nodes.length} | Zoom: ${(zoom * 100).toFixed(0)}% | Pan: ${panX.toFixed(0)}, ${panY.toFixed(0)}`;
    }

    function navigateToPosition(canvasX, canvasY) {
        const worldPos = canvasToWorld(canvasX, canvasY);
        if (!worldPos) return;

        const app = getApp();
        const mainCanvas = document.querySelector('canvas');
        if (!app?.canvas?.ds || !mainCanvas) return;

        try {
            // Center the main canvas on the clicked world position
            app.canvas.ds.offset[0] = -worldPos.x + mainCanvas.width / 2;
            app.canvas.ds.offset[1] = -worldPos.y + mainCanvas.height / 2;
            app.canvas.setDirty(true, true);
            
            // Update minimap to reflect the change
            setTimeout(() => drawMinimap(), 50);
        } catch (err) {
            console.log("❌ Navigation error:", err);
        }
    }

    function isClickInViewport(canvasX, canvasY) {
        const app = getApp();
        if (!app?.canvas?.ds) return false;
        
        const ds = app.canvas.ds;
        const mainCanvas = document.querySelector('canvas');
        if (!mainCanvas) return false;
        
        const worldPos = canvasToWorld(canvasX, canvasY);
        if (!worldPos) return false;
        
        // Check if click is inside viewport rectangle in world coordinates
        const viewportX = -ds.offset[0];
        const viewportY = -ds.offset[1];
        const viewportW = mainCanvas.width / ds.scale;
        const viewportH = mainCanvas.height / ds.scale;
        
        return worldPos.x >= viewportX && worldPos.x <= viewportX + viewportW &&
               worldPos.y >= viewportY && worldPos.y <= viewportY + viewportH;
    }

    function adjustPanToKeepNodesVisible() {
        const nodes = getNodes();
        if (!nodes?.length) return;

        const canvas = currentDialog?.querySelector('canvas');
        if (!canvas) return;

        // Calculate bounds
        const bounds = nodes.reduce((acc, n) => {
            const x = n.pos?.[0] ?? n.x ?? 0;
            const y = n.pos?.[1] ?? n.y ?? 0;
            const w = n.size?.[0] ?? n.width ?? 100;
            const h = n.size?.[1] ?? n.height ?? 60;
            
            return {
                minX: Math.min(acc.minX, x),
                minY: Math.min(acc.minY, y),
                maxX: Math.max(acc.maxX, x + w),
                maxY: Math.max(acc.maxY, y + h)
            };
        }, { minX: Infinity, minY: Infinity, maxX: -Infinity, maxY: -Infinity });

        const width = bounds.maxX - bounds.minX;
        const height = bounds.maxY - bounds.minY;
        if (width <= 0 || height <= 0) return;

        const baseScale = Math.min(canvas.width / Math.max(width, 1000), canvas.height / Math.max(height, 1000));
        const scale = baseScale * zoom;

        // If zoomed in too much, adjust pan to keep nodes centered
        if (zoom > 2) {
            const maxPanX = canvas.width / 4;
            const maxPanY = canvas.height / 4;
            panX = Math.max(-maxPanX, Math.min(maxPanX, panX));
            panY = Math.max(-maxPanY, Math.min(maxPanY, panY));
        }
    }

    function setupEventHandlers() {
        const canvas = currentDialog.querySelector('canvas');
        let isViewportDragging = false;
        
        // Mouse handlers
        canvas.addEventListener('mousedown', (e) => {
            dragStartTime = Date.now();
            dragStartX = e.clientX;
            dragStartY = e.clientY;
            
            const rect = canvas.getBoundingClientRect();
            const canvasX = e.clientX - rect.left;
            const canvasY = e.clientY - rect.top;
            
            // Check if clicking inside viewport indicator
            isViewportDragging = isClickInViewport(canvasX, canvasY);
            
            if (isViewportDragging) {
                canvas.style.cursor = 'grab';
            }
        });

        canvas.addEventListener('mousemove', (e) => {
            if (!dragStartTime) return;
            
            const totalDelta = Math.abs(e.clientX - dragStartX) + Math.abs(e.clientY - dragStartY);
            
            if (totalDelta > DRAG_THRESHOLD && !isDragging) {
                isDragging = true;
                if (isViewportDragging) {
                    canvas.style.cursor = 'grabbing';
                } else {
                    canvas.style.cursor = 'move';
                }
            }
            
            if (isDragging) {
                if (isViewportDragging) {
                    // Move the viewport - convert movement to world coordinates
                    const app = getApp();
                    if (app?.canvas?.ds) {
                        const transform = getTransformState();
                        if (transform) {
                            // Scale movement by the inverse of the minimap scale
                            const movementScale = 1 / transform.scale;
                            app.canvas.ds.offset[0] -= e.movementX * movementScale;
                            app.canvas.ds.offset[1] -= e.movementY * movementScale;
                            app.canvas.setDirty(true, true);
                        }
                    }
                } else {
                    // Pan the minimap view
                    panX += e.movementX;
                    panY += e.movementY;
                }
                drawMinimap();
            }
        });

        canvas.addEventListener('mouseup', (e) => {
            const clickDuration = Date.now() - dragStartTime;
            const totalMovement = Math.abs(e.clientX - dragStartX) + Math.abs(e.clientY - dragStartY);
            
            if (!isDragging && clickDuration < 500 && totalMovement < DRAG_THRESHOLD) {
                if (!isViewportDragging) {
                    // Regular click-to-navigate (only if not clicking viewport)
                    const rect = canvas.getBoundingClientRect();
                    navigateToPosition(e.clientX - rect.left, e.clientY - rect.top);
                }
            }
            
            isDragging = false;
            isViewportDragging = false;
            dragStartTime = 0;
            canvas.style.cursor = 'crosshair';
        });

        canvas.addEventListener('wheel', (e) => {
            e.preventDefault();
            const oldZoom = zoom;
            zoom = Math.max(0.1, Math.min(5, zoom * (e.deltaY > 0 ? 0.9 : 1.1)));
            
            // Adjust pan to keep content centered when zooming
            if (zoom !== oldZoom) {
                adjustPanToKeepNodesVisible();
            }
            
            drawMinimap();
        });

        // Button handlers
        currentDialog.querySelector('#close-btn').onclick = () => closeDialog();
        currentDialog.querySelector('#legend-btn').onclick = () => {
            const legend = currentDialog.querySelector('.legend');
            const isVisible = legend.style.display !== 'none';
            legend.style.display = isVisible ? 'none' : 'block';
            if (!isVisible) updateLegend();
        };
        currentDialog.querySelector('#zoom-in').onclick = () => {
            zoom = Math.min(zoom * 1.2, 5);
            adjustPanToKeepNodesVisible();
            drawMinimap();
        };
        currentDialog.querySelector('#zoom-out').onclick = () => {
            zoom = Math.max(zoom / 1.2, 0.1);
            adjustPanToKeepNodesVisible();
            drawMinimap();
        };
        currentDialog.querySelector('#zoom-reset').onclick = () => {
            zoom = 1;
            panX = panY = 0;
            drawMinimap();
        };

        // ESC key
        const escHandler = (e) => e.key === 'Escape' && closeDialog();
        document.addEventListener('keydown', escHandler);
        
        return escHandler;
    }

    function createMinimapDialog() {
        if (currentDialog) return;

        const colors = getComfyUIColors();
        const { containerWidth, containerHeight, canvasWidth, canvasHeight } = calculateDimensions();

        // Clean up existing style
        document.getElementById('minimap-style')?.remove();

        // Create style tag
        const style = document.createElement('style');
        style.id = 'minimap-style';
        style.textContent = createStyleCSS(colors);
        document.head.appendChild(style);

        // Create container
        const container = document.createElement('div');
        container.id = 'endless-minimap';
        container.style.cssText = `
            position: fixed;
            top: 100px;
            right: 20px;
            width: ${containerWidth}px;
            height: ${containerHeight}px;
            background: ${colors.menu};
            color: ${colors.inputText};
            border: 1px solid ${colors.accent};
            border-radius: 8px;
            box-shadow: ${colors.shadow || '0 4px 12px rgba(0, 0, 0, 0.25)'};
            z-index: 99999;
            padding: 0;
            overflow: hidden;
            display: flex;
            flex-direction: column;
        `;

        container.innerHTML = `
            <div class="drag-bar">
                <span>Endless 🌊✨ Minimap</span>
                <div style="float: right; margin-top: -2px;">
                    <button id="legend-btn" title="Toggle legend">🎨</button>
                    <button id="zoom-out" title="Zoom out">▫️</button>
                    <button id="zoom-reset" title="Reset zoom and pan">🏠</button>
                    <button id="zoom-in" title="Zoom in">⬜</button>
                    <button id="close-btn" title="Close minimap">❌</button>
                </div>
            </div>
            <div style="flex: 1; position: relative; overflow: hidden;">
                <canvas width="${canvasWidth}" height="${canvasHeight}" style="display: block; cursor: crosshair; position: absolute; top: 0; left: 0; width: 100%; height: 100%;"></canvas>
                <div class="legend"></div>
            </div>
            <div class="pan-info">Nodes: 0 | Zoom: 100% | Pan: 0, 0</div>
        `;

        document.body.appendChild(container);
        currentDialog = container;

        // Setup dragging
        makeDraggable(container, container.querySelector('.drag-bar'));

        // Setup event handlers
        const escHandler = setupEventHandlers();

        // Setup resize observer
        resizeObserver = new ResizeObserver(() => {
            const newAspectRatio = getCanvasAspectRatio();
            const canvas = container.querySelector('canvas');
            const currentAspectRatio = canvas.width / canvas.height;
            
            if (Math.abs(newAspectRatio - currentAspectRatio) > 0.1) {
                const { containerWidth: newContainerWidth, containerHeight: newContainerHeight, canvasWidth: newCanvasWidth, canvasHeight: newCanvasHeight } = calculateDimensions();
                
                // Update container size
                container.style.width = `${newContainerWidth}px`;
                container.style.height = `${newContainerHeight}px`;
                
                // Update canvas size
                canvas.width = newCanvasWidth;
                canvas.height = newCanvasHeight;
                
                drawMinimap();
            }
        });

        const mainCanvas = document.querySelector('canvas');
        if (mainCanvas) resizeObserver.observe(mainCanvas);
        resizeObserver.observe(document.body);

        // Setup theme updates
        unregisterThemeCallback = onThemeChange(updateTheme);

        // Start animation loop
        function updateLoop() {
            drawMinimap();
            animationId = setTimeout(updateLoop, 1000);
        }
        updateLoop();

        // Setup cleanup
        const originalRemove = container.remove.bind(container);
        container.remove = function() {
            clearTimeout(animationId);
            document.removeEventListener('keydown', escHandler);
            resizeObserver?.disconnect();
            unregisterThemeCallback?.();
            document.getElementById('minimap-style')?.remove();
            currentDialog = null;
            animationId = null;
            unregisterThemeCallback = null;
            resizeObserver = null;
            originalRemove();
        };
    }

    function closeDialog() {
        currentDialog?.remove();
    }

    // Register tool
    registerEndlessTool("Minimap", createMinimapDialog);
})();