/**
 * Hexagonal Magnetism Background - OPTIMIZED
 * Only renders visible hexagons, uses viewport culling
 */

(function() {
    'use strict';

    // Configuration
    const CONFIG = {
        hexSize: 30,
        lineWidth: 1,
        maxLineWidth: 2.5,
        baseOpacity: 0.15,
        maxOpacity: 0.6,
        magnetRadius: 280,
        maxDisplacement: 12,
        returnSpeed: 0.4,
        // Pre-calculated colors
        baseR: 119, baseG: 119, baseB: 100,
        tealR: 38, tealG: 166, tealB: 154,
        orangeR: 245, orangeG: 124, orangeB: 0
    };

    // Pre-calculate hex geometry
    const SQRT3 = Math.sqrt(3);
    const horizSpacing = CONFIG.hexSize * SQRT3;
    const vertSpacing = CONFIG.hexSize * 1.5;
    
    // Pre-calculate hex vertices angles (pointy-top)
    const HEX_ANGLES = [];
    for (let i = 0; i < 6; i++) {
        const angle = (Math.PI / 3) * i - Math.PI / 2;
        HEX_ANGLES.push({ cos: Math.cos(angle), sin: Math.sin(angle) });
    }

    // State
    let canvas, ctx;
    let mouse = { x: -1000, y: -1000 };
    let scrollY = 0;
    let animationId;
    let isInitialized = false;
    let canvasWidth = 0;
    let canvasHeight = 0;
    
    // Active hexagons (only those being animated)
    let activeHexagons = new Map();

    // Easing function
    function easeOutCubic(t) {
        return 1 - (1 - t) * (1 - t) * (1 - t);
    }

    // Get hex key from grid position
    function getHexKey(col, row) {
        return `${col},${row}`;
    }

    // Get hex origin from grid position
    function getHexOrigin(col, row) {
        const xOffset = (row % 2 === 1) ? horizSpacing / 2 : 0;
        return {
            x: col * horizSpacing + xOffset,
            y: row * vertSpacing
        };
    }

    // Draw a single hexagon
    function drawHex(x, y, opacity, lineWidth, colorInfluence) {
        ctx.beginPath();
        ctx.moveTo(
            x + CONFIG.hexSize * HEX_ANGLES[0].cos,
            y + CONFIG.hexSize * HEX_ANGLES[0].sin
        );
        for (let i = 1; i < 6; i++) {
            ctx.lineTo(
                x + CONFIG.hexSize * HEX_ANGLES[i].cos,
                y + CONFIG.hexSize * HEX_ANGLES[i].sin
            );
        }
        ctx.closePath();

        // Color calculation
        let r, g, b;
        if (colorInfluence < 0.01) {
            r = CONFIG.baseR; g = CONFIG.baseG; b = CONFIG.baseB;
        } else if (colorInfluence < 0.6) {
            const t = colorInfluence / 0.6;
            r = CONFIG.baseR + (CONFIG.tealR - CONFIG.baseR) * t | 0;
            g = CONFIG.baseG + (CONFIG.tealG - CONFIG.baseG) * t | 0;
            b = CONFIG.baseB + (CONFIG.tealB - CONFIG.baseB) * t | 0;
        } else {
            const t = (colorInfluence - 0.6) / 0.4;
            r = CONFIG.tealR + (CONFIG.orangeR - CONFIG.tealR) * t | 0;
            g = CONFIG.tealG + (CONFIG.orangeG - CONFIG.tealG) * t | 0;
            b = CONFIG.tealB + (CONFIG.orangeB - CONFIG.tealB) * t | 0;
        }
        
        ctx.strokeStyle = `rgba(${r},${g},${b},${opacity})`;
        ctx.lineWidth = lineWidth;
        ctx.stroke();
    }

    // Initialize
    function init() {
        canvas = document.getElementById('hexCanvas');
        if (!canvas) return;

        ctx = canvas.getContext('2d', { alpha: true });
        resize();

        window.addEventListener('resize', debounce(resize, 200));
        document.addEventListener('mousemove', handleMouseMove, { passive: true });
        document.addEventListener('mouseleave', handleMouseLeave);
        window.addEventListener('scroll', handleScroll, { passive: true });

        isInitialized = true;
        animate();
    }

    function resize() {
        const dpr = Math.min(window.devicePixelRatio || 1, 2); // Cap DPR at 2
        canvasWidth = window.innerWidth;
        canvasHeight = window.innerHeight;
        
        canvas.width = canvasWidth * dpr;
        canvas.height = canvasHeight * dpr;
        canvas.style.width = canvasWidth + 'px';
        canvas.style.height = canvasHeight + 'px';
        canvas.style.position = 'fixed';
        canvas.style.top = '0';
        canvas.style.left = '0';
        
        ctx.setTransform(1, 0, 0, 1, 0, 0);
        ctx.scale(dpr, dpr);
    }

    function handleMouseMove(e) {
        mouse.x = e.clientX;
        mouse.y = e.clientY;
    }

    function handleMouseLeave() {
        mouse.x = -1000;
        mouse.y = -1000;
    }

    function handleScroll() {
        scrollY = window.scrollY;
    }

    // Main animation loop - optimized
    function animate() {
        if (!isInitialized) return;

        ctx.clearRect(0, 0, canvasWidth, canvasHeight);

        // Calculate visible grid range (viewport only)
        const viewTop = scrollY - CONFIG.hexSize;
        const viewBottom = scrollY + canvasHeight + CONFIG.hexSize;
        const viewLeft = -CONFIG.hexSize;
        const viewRight = canvasWidth + CONFIG.hexSize;

        const startRow = Math.floor(viewTop / vertSpacing) - 1;
        const endRow = Math.ceil(viewBottom / vertSpacing) + 1;
        const startCol = Math.floor(viewLeft / horizSpacing) - 1;
        const endCol = Math.ceil(viewRight / horizSpacing) + 1;

        // Mouse position in world coordinates
        const mouseWorldY = mouse.y + scrollY;
        const magnetRadiusSq = CONFIG.magnetRadius * CONFIG.magnetRadius;

        // Update active hexagons
        for (const [key, hex] of activeHexagons) {
            const dx = mouse.x - hex.originX;
            const dy = mouseWorldY - hex.originY;
            const distSq = dx * dx + dy * dy;

            if (distSq < magnetRadiusSq && mouse.x > -500) {
                const distance = Math.sqrt(distSq);
                const influence = 1 - (distance / CONFIG.magnetRadius);
                const easedInfluence = easeOutCubic(influence);
                const angle = Math.atan2(dy, dx);
                const displacement = CONFIG.maxDisplacement * easedInfluence;

                hex.currentX += (hex.originX + Math.cos(angle) * displacement - hex.currentX) * 0.15;
                hex.currentY += (hex.originY + Math.sin(angle) * displacement - hex.currentY) * 0.15;
                hex.opacity = CONFIG.baseOpacity + (CONFIG.maxOpacity - CONFIG.baseOpacity) * easedInfluence;
                hex.lineWidth = CONFIG.lineWidth + (CONFIG.maxLineWidth - CONFIG.lineWidth) * easedInfluence;
                hex.colorInfluence = easedInfluence;
            } else {
                // Return to origin
                hex.currentX += (hex.originX - hex.currentX) * CONFIG.returnSpeed;
                hex.currentY += (hex.originY - hex.currentY) * CONFIG.returnSpeed;
                hex.opacity += (CONFIG.baseOpacity - hex.opacity) * CONFIG.returnSpeed;
                hex.lineWidth += (CONFIG.lineWidth - hex.lineWidth) * CONFIG.returnSpeed;
                hex.colorInfluence *= (1 - CONFIG.returnSpeed);

                // Remove if fully reset
                if (hex.colorInfluence < 0.001 && 
                    Math.abs(hex.currentX - hex.originX) < 0.1 &&
                    Math.abs(hex.currentY - hex.originY) < 0.1) {
                    activeHexagons.delete(key);
                }
            }
        }

        // Draw visible hexagons
        for (let row = startRow; row <= endRow; row++) {
            for (let col = startCol; col <= endCol; col++) {
                const origin = getHexOrigin(col, row);
                const screenY = origin.y - scrollY;
                
                // Skip if outside viewport
                if (screenY < -CONFIG.hexSize || screenY > canvasHeight + CONFIG.hexSize) continue;

                const key = getHexKey(col, row);
                const activeHex = activeHexagons.get(key);

                if (activeHex) {
                    // Draw animated hex
                    drawHex(
                        activeHex.currentX,
                        activeHex.currentY - scrollY,
                        activeHex.opacity,
                        activeHex.lineWidth,
                        activeHex.colorInfluence
                    );
                } else {
                    // Check if should become active
                    const dx = mouse.x - origin.x;
                    const dy = mouseWorldY - origin.y;
                    const distSq = dx * dx + dy * dy;

                    if (distSq < magnetRadiusSq && mouse.x > -500) {
                        // Add to active hexagons
                        activeHexagons.set(key, {
                            originX: origin.x,
                            originY: origin.y,
                            currentX: origin.x,
                            currentY: origin.y,
                            opacity: CONFIG.baseOpacity,
                            lineWidth: CONFIG.lineWidth,
                            colorInfluence: 0
                        });
                    }

                    // Draw static hex
                    drawHex(origin.x, screenY, CONFIG.baseOpacity, CONFIG.lineWidth, 0);
                }
            }
        }

        animationId = requestAnimationFrame(animate);
    }

    function debounce(func, wait) {
        let timeout;
        return function(...args) {
            clearTimeout(timeout);
            timeout = setTimeout(() => func(...args), wait);
        };
    }

    function destroy() {
        if (animationId) cancelAnimationFrame(animationId);
        isInitialized = false;
        activeHexagons.clear();
    }

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
    } else {
        init();
    }

    window.HexBackground = { init, destroy, config: CONFIG };
})();
