const initZeldaFujiBackground = () => {
    // Get the canvas element
    const canvas = document.getElementById('bg-canvas');
    if (!canvas) return;
    
    // Create scene, camera, and renderer
    const scene = new THREE.Scene();
    const camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 1000);
    const renderer = new THREE.WebGLRenderer({ canvas, antialias: true });
    
    // Set renderer size and pixel ratio
    renderer.setSize(window.innerWidth, window.innerHeight);
    renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
    
    // Create a gradient background (sky)
    const vertexShader = `
        varying vec2 vUv;
        void main() {
            vUv = uv;
            gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
        }
    `;
    
    const fragmentShader = `
        uniform float time;
        varying vec2 vUv;
        
        vec3 skyColor1 = vec3(0.1, 0.2, 0.4); // Dark blue
        vec3 skyColor2 = vec3(0.5, 0.7, 0.9); // Light blue
        vec3 horizonColor = vec3(0.9, 0.7, 0.5); // Sunset orange
        
        void main() {
            // Time-based color shift for day/night cycle
            float dayFactor = (sin(time * 0.05) + 1.0) * 0.5;
            
            // Create gradient based on Y coordinate
            float gradient = smoothstep(0.0, 0.7, vUv.y);
            
            // Horizon glow
            float horizon = smoothstep(0.4, 0.5, vUv.y) * smoothstep(0.6, 0.5, vUv.y);
            
            // Blend sky colors with horizon
            vec3 finalColor = mix(skyColor1, skyColor2, gradient * dayFactor);
            finalColor = mix(finalColor, horizonColor, horizon * (0.5 + 0.5 * dayFactor));
            
            // Add stars at night
            if (dayFactor < 0.5) {
                float nightness = 1.0 - dayFactor * 2.0;
                
                // Create subtle stars
                vec2 pos = vUv * vec2(100.0, 50.0);
                vec2 seed = floor(pos);
                
                // Random star positions
                float random = fract(sin(dot(seed, vec2(12.9898, 78.233))) * 43758.5453);
                
                // Only show some points as stars
                if (random > 0.97) {
                    float starBrightness = fract(random * 10.0) * nightness;
                    finalColor += vec3(1.0, 1.0, 0.9) * starBrightness;
                }
            }
            
            gl_FragColor = vec4(finalColor, 1.0);
        }
    `;
    
    // Create sky background
    const skyGeometry = new THREE.PlaneGeometry(2, 2);
    const skyMaterial = new THREE.ShaderMaterial({
        uniforms: {
            time: { value: 0 }
        },
        vertexShader: vertexShader,
        fragmentShader: fragmentShader,
        depthWrite: false
    });
    
    const sky = new THREE.Mesh(skyGeometry, skyMaterial);
    sky.renderOrder = -1000; // Render first (background)
    scene.add(sky);
    
    // Create Mount Fuji
    const fujiGeometry = new THREE.ConeGeometry(5, 8, 32, 1, true);
    
    // Custom vertex shader for Mount Fuji to add terrain variation
    const fujiVertexShader = `
        varying vec2 vUv;
        varying float vHeight;
        
        // Simple noise function
        float noise(vec2 p) {
            return fract(sin(dot(p, vec2(12.9898, 78.233))) * 43758.5453);
        }
        
        // FBM (Fractal Brownian Motion) for more natural terrain
        float fbm(vec2 p) {
            float value = 0.0;
            float amplitude = 0.5;
            float frequency = 1.0;
            for (int i = 0; i < 5; i++) {
                value += amplitude * noise(p * frequency);
                amplitude *= 0.5;
                frequency *= 2.0;
            }
            return value;
        }
        
        void main() {
            vUv = uv;
            vHeight = position.y / 8.0; // Normalized height
            
            // Add terrain variation based on position
            vec3 newPosition = position;
            
            // Only add variation to the sides, keep the peak smooth
            if (vHeight < 0.8) {
                // Add rocky features based on height and angle
                float angle = atan(position.z, position.x);
                float radius = length(position.xz);
                
                // More variation at lower elevations
                float variation = fbm(vec2(angle * 5.0, vHeight * 10.0)) * (1.0 - vHeight) * 0.2;
                
                // Apply variation to radius
                float newRadius = radius * (1.0 + variation);
                newPosition.x = cos(angle) * newRadius;
                newPosition.z = sin(angle) * newRadius;
            }
            
            // Apply slight vertical variation
            if (vHeight > 0.2 && vHeight < 0.9) {
                newPosition.y += fbm(vec2(newPosition.x * 0.5, newPosition.z * 0.5)) * 0.1;
            }
            
            gl_Position = projectionMatrix * modelViewMatrix * vec4(newPosition, 1.0);
        }
    `;
    
    // Custom fragment shader for Mount Fuji with snow
    const fujiFragmentShader = `
        uniform float time;
        varying vec2 vUv;
        varying float vHeight;
        
        // Noise function for texture variation
        float noise(vec2 p) {
            return fract(sin(dot(p, vec2(12.9898, 78.233))) * 43758.5453);
        }
        
        // FBM function
        float fbm(vec2 p) {
            float value = 0.0;
            float amplitude = 0.5;
            float frequency = 1.0;
            for (int i = 0; i < 5; i++) {
                value += amplitude * noise(p * frequency);
                amplitude *= 0.5;
                frequency *= 2.0;
            }
            return value;
        }
        
        void main() {
            // Base mountain color
            vec3 rockColor = vec3(0.15, 0.15, 0.2); // Dark rock
            vec3 grassColor = vec3(0.2, 0.3, 0.15); // Dark grass
            vec3 snowColor = vec3(0.95, 0.95, 1.0); // Bright snow
            
            // Terrain variation
            float terrainNoise = fbm(vUv * 20.0);
            
            // Snow line with some variation
            float snowLine = 0.6 + terrainNoise * 0.1;
            float snowBlend = smoothstep(snowLine - 0.1, snowLine + 0.1, vHeight);
            
            // Mix rock and grass based on height
            float grassLine = 0.3 + terrainNoise * 0.05;
            float grassBlend = smoothstep(0.1, grassLine, vHeight) * (1.0 - snowBlend);
            
            // Combine colors
            vec3 mountainColor = rockColor;
            mountainColor = mix(mountainColor, grassColor, grassBlend);
            mountainColor = mix(mountainColor, snowColor, snowBlend);
            
            // Add texture detail
            float detailNoise = fbm(vUv * 50.0) * 0.1;
            mountainColor *= 1.0 - detailNoise;
            
            // Add shadow based on angle
            float shadow = 0.7 + 0.3 * sin(time * 0.2 + 3.14);
            
            gl_FragColor = vec4(mountainColor * shadow, 1.0);
        }
    `;
    
    const fujiMaterial = new THREE.ShaderMaterial({
        uniforms: {
            time: { value: 0 }
        },
        vertexShader: fujiVertexShader,
        fragmentShader: fujiFragmentShader,
        side: THREE.DoubleSide
    });
    
    const fuji = new THREE.Mesh(fujiGeometry, fujiMaterial);
    fuji.position.y = -4; // Position bottom at lower part of screen
    scene.add(fuji);
    
    // Create smoke particles at the top of Mount Fuji
    const smokeCount = 200;
    const smokeParticlesGeometry = new THREE.BufferGeometry();
    const smokePositions = new Float32Array(smokeCount * 3);
    const smokeSizes = new Float32Array(smokeCount);
    const smokeOpacities = new Float32Array(smokeCount);
    const smokeAges = new Float32Array(smokeCount);
    const smokeMaxAges = new Float32Array(smokeCount);
    
    // Initialize smoke particles
    for (let i = 0; i < smokeCount; i++) {
        resetSmokeParticle(i, true);
    }
    
    function resetSmokeParticle(index, initial = false) {
        const i3 = index * 3;
        
        // Random angle around the peak
        const angle = Math.random() * Math.PI * 2;
        const radius = Math.random() * 0.3; // Small radius at the peak
        
        // Position at the peak of Fuji with some randomness
        smokePositions[i3] = Math.cos(angle) * radius;
        smokePositions[i3 + 1] = 4 + Math.random() * 0.2; // At the peak
        smokePositions[i3 + 2] = Math.sin(angle) * radius;
        
        // Random size
        smokeSizes[index] = 0.1 + Math.random() * 0.4;
        
        // If initial setup, distribute ages so not all smoke appears at once
        if (initial) {
            smokeAges[index] = Math.random() * 5;
        } else {
            smokeAges[index] = 0;
        }
        
        // Maximum age before particle resets
        smokeMaxAges[index] = 5 + Math.random() * 3;
        
        // Initial opacity
        smokeOpacities[index] = Math.random() * 0.3 + 0.1;
    }
    
    smokeParticlesGeometry.setAttribute('position', new THREE.BufferAttribute(smokePositions, 3));
    smokeParticlesGeometry.setAttribute('size', new THREE.BufferAttribute(smokeSizes, 1));
    smokeParticlesGeometry.setAttribute('opacity', new THREE.BufferAttribute(smokeOpacities, 1));
    
    // Create smoke texture
    const smokeCanvas = document.createElement('canvas');
    smokeCanvas.width = 128;
    smokeCanvas.height = 128;
    const ctx = smokeCanvas.getContext('2d');
    
    // Create radial gradient for smoke
    const gradient = ctx.createRadialGradient(64, 64, 0, 64, 64, 64);
    gradient.addColorStop(0, 'rgba(255, 255, 255, 1)');
    gradient.addColorStop(0.2, 'rgba(230, 230, 230, 0.9)');
    gradient.addColorStop(0.5, 'rgba(200, 200, 210, 0.5)');
    gradient.addColorStop(0.8, 'rgba(180, 180, 200, 0.2)');
    gradient.addColorStop(1, 'rgba(180, 180, 220, 0)');
    
    ctx.fillStyle = gradient;
    ctx.fillRect(0, 0, 128, 128);
    
    const smokeTexture = new THREE.Texture(smokeCanvas);
    smokeTexture.needsUpdate = true;
    
    // Zelda-style smoke shader with swirling patterns
    const smokeVertexShader = `
        attribute float size;
        attribute float opacity;
        uniform float time;
        
        varying float vOpacity;
        varying vec3 vPosition;
        
        void main() {
            vOpacity = opacity;
            vPosition = position;
            
            vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);
            
            // Size attenuates with distance
            gl_PointSize = size * (20.0 / -mvPosition.z);
            gl_Position = projectionMatrix * mvPosition;
        }
    `;
    
    const smokeFragmentShader = `
        uniform sampler2D smokeTexture;
        uniform float time;
        
        varying float vOpacity;
        varying vec3 vPosition;
        
        // Zelda-inspired swirl patterns
        float swirl(vec2 uv, float time) {
            float angle = atan(uv.y - 0.5, uv.x - 0.5);
            float dist = length(uv - 0.5);
            
            // Create swirling patterns
            float pattern = sin(dist * 10.0 - time * 2.0 + angle * 5.0) * 0.5 + 0.5;
            return pattern * smoothstep(0.5, 0.0, dist);
        }
        
        void main() {
            // Basic smoke texture
            vec4 smokeColor = texture2D(smokeTexture, gl_PointCoord);
            
            // Add Zelda-inspired magical swirls
            vec2 centeredUV = gl_PointCoord;
            float swirlEffect = swirl(centeredUV, time + vPosition.x + vPosition.y);
            
            // Create blue-green magical effect
            vec3 magicColor = mix(
                vec3(0.2, 0.5, 0.8), // Blue
                vec3(0.2, 0.8, 0.5), // Green
                swirlEffect
            );
            
            // Mix magic effect with smoke
            vec3 finalColor = mix(smokeColor.rgb, magicColor, swirlEffect * 0.5);
            
            // Apply opacity
            float finalOpacity = smokeColor.a * vOpacity;
            
            // Discard nearly transparent pixels
            if (finalOpacity < 0.01) discard;
            
            gl_FragColor = vec4(finalColor, finalOpacity);
        }
    `;
    
    const smokeMaterial = new THREE.ShaderMaterial({
        uniforms: {
            smokeTexture: { value: smokeTexture },
            time: { value: 0 }
        },
        vertexShader: smokeVertexShader,
        fragmentShader: smokeFragmentShader,
        transparent: true,
        depthWrite: false,
        blending: THREE.AdditiveBlending
    });
    
    const smokeParticles = new THREE.Points(smokeParticlesGeometry, smokeMaterial);
    smokeParticles.renderOrder = 10; // Render after mountain
    scene.add(smokeParticles);
    
    // Add some Zelda-style magical sparkles
    const sparkleCount = 50;
    const sparkleGeometry = new THREE.BufferGeometry();
    const sparklePositions = new Float32Array(sparkleCount * 3);
    const sparkleSizes = new Float32Array(sparkleCount);
    const sparkleColors = new Float32Array(sparkleCount * 3);
    
    // Initialize sparkles
    for (let i = 0; i < sparkleCount; i++) {
        const i3 = i * 3;
        
        // Position sparkles around the smoke area
        const angle = Math.random() * Math.PI * 2;
        const radius = 0.3 + Math.random() * 0.8;
        const height = 4 + Math.random() * 1.5;
        
        sparklePositions[i3] = Math.cos(angle) * radius;
        sparklePositions[i3 + 1] = height;
        sparklePositions[i3 + 2] = Math.sin(angle) * radius;
        
        // Size
        sparkleSizes[i] = 0.05 + Math.random() * 0.1;
        
        // Color - based on Zelda magical effects
        if (Math.random() < 0.5) {
            // Blue sparkles
            sparkleColors[i3] = 0.2 + Math.random() * 0.3;
            sparkleColors[i3 + 1] = 0.5 + Math.random() * 0.3;
            sparkleColors[i3 + 2] = 0.8 + Math.random() * 0.2;
        } else {
            // Green sparkles
            sparkleColors[i3] = 0.2 + Math.random() * 0.2;
            sparkleColors[i3 + 1] = 0.7 + Math.random() * 0.3;
            sparkleColors[i3 + 2] = 0.3 + Math.random() * 0.3;
        }
    }
    
    sparkleGeometry.setAttribute('position', new THREE.BufferAttribute(sparklePositions, 3));
    sparkleGeometry.setAttribute('size', new THREE.BufferAttribute(sparkleSizes, 1));
    sparkleGeometry.setAttribute('color', new THREE.BufferAttribute(sparkleColors, 3));
    
    // Sparkle material
    const sparkleVertexShader = `
        attribute float size;
        attribute vec3 color;
        
        varying vec3 vColor;
        
        void main() {
            vColor = color;
            vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);
            gl_PointSize = size * (50.0 / -mvPosition.z);
            gl_Position = projectionMatrix * mvPosition;
        }
    `;
    
    const sparkleFragmentShader = `
        uniform float time;
        
        varying vec3 vColor;
        
        void main() {
            // Create star shape
            vec2 uv = gl_PointCoord * 2.0 - 1.0;
            float star = 1.0 - length(uv);
            
            // Add sparkle effect
            float sparkle = sin(time * 10.0) * 0.5 + 0.5;
            
            // Final color with pulsing
            vec3 finalColor = vColor * (1.0 + sparkle * 0.5);
            float alpha = star * (0.5 + sparkle * 0.5);
            
            // Sharp cutoff for star shape
            if (star < 0.2) discard;
            
            gl_FragColor = vec4(finalColor, alpha);
        }
    `;
    
    const sparkleMaterial = new THREE.ShaderMaterial({
        uniforms: {
            time: { value: 0 }
        },
        vertexShader: sparkleVertexShader,
        fragmentShader: sparkleFragmentShader,
        transparent: true,
        depthWrite: false,
        blending: THREE.AdditiveBlending
    });
    
    const sparkles = new THREE.Points(sparkleGeometry, sparkleMaterial);
    sparkles.renderOrder = 11;
    scene.add(sparkles);
    
    // Position camera
    camera.position.z = 12;
    camera.position.y = 1;
    
    // Handle window resize
    window.addEventListener('resize', () => {
        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();
        renderer.setSize(window.innerWidth, window.innerHeight);
    });
    
    // Animation loop
    const clock = new THREE.Clock();
    
    const animate = () => {
        const elapsedTime = clock.getElapsedTime();
        const deltaTime = clock.getDelta();
        
        // Slowly rotate Mount Fuji
        fuji.rotation.y = elapsedTime * 0.05;
        
        // Rotate smoke and sparkles to always face camera
        smokeParticles.rotation.y = fuji.rotation.y;
        sparkles.rotation.y = fuji.rotation.y;
        
        // Update time uniform for shaders
        skyMaterial.uniforms.time.value = elapsedTime;
        fujiMaterial.uniforms.time.value = elapsedTime;
        smokeMaterial.uniforms.time.value = elapsedTime;
        sparkleMaterial.uniforms.time.value = elapsedTime;
        
        // Animate smoke particles
        const smokePositionsAttr = smokeParticles.geometry.getAttribute('position');
        const smokeSizesAttr = smokeParticles.geometry.getAttribute('size');
        const smokeOpacitiesAttr = smokeParticles.geometry.getAttribute('opacity');
        
        for (let i = 0; i < smokeCount; i++) {
            const i3 = i * 3;
            
            // Update smoke age
            smokeAges[i] += deltaTime;
            
            // Get current position
            let x = smokePositionsAttr.array[i3];
            let y = smokePositionsAttr.array[i3 + 1];
            let z = smokePositionsAttr.array[i3 + 2];
            
            // Move smoke upward and outward
            const ageRatio = smokeAges[i] / smokeMaxAges[i];
            
            // Calculate smoke rise pattern
            smokePositionsAttr.array[i3] += Math.sin(elapsedTime * 0.5 + i) * 0.01;
            smokePositionsAttr.array[i3 + 1] += (0.1 + ageRatio * 0.1) * deltaTime;
            smokePositionsAttr.array[i3 + 2] += Math.cos(elapsedTime * 0.5 + i * 0.7) * 0.01;
            
            // Increase size as smoke rises
            smokeSizesAttr.array[i] = smokeSizes[i] * (0.5 + ageRatio * 0.5);
            
            // Fade out over lifetime
            smokeOpacitiesAttr.array[i] = smokeOpacities[i] * (1.0 - ageRatio * ageRatio);
            
            // Reset if too old
            if (smokeAges[i] >= smokeMaxAges[i]) {
                resetSmokeParticle(i);
            }
        }
        
        smokePositionsAttr.needsUpdate = true;
        smokeSizesAttr.needsUpdate = true;
        smokeOpacitiesAttr.needsUpdate = true;
        
        // Animate sparkles
        const sparklePositionsAttr = sparkles.geometry.getAttribute('position');
        const sparkleSizesAttr = sparkles.geometry.getAttribute('size');
        
        for (let i = 0; i < sparkleCount; i++) {
            const i3 = i * 3;
            
            // Spiral movement around the smoke
            const angle = Math.atan2(
                sparklePositionsAttr.array[i3 + 2],
                sparklePositionsAttr.array[i3]
            );
            
            const radius = Math.sqrt(
                sparklePositionsAttr.array[i3] * sparklePositionsAttr.array[i3] + 
                sparklePositionsAttr.array[i3 + 2] * sparklePositionsAttr.array[i3 + 2]
            );
            
            // Update position with spiral movement
            const newAngle = angle + deltaTime * (0.2 + Math.sin(i) * 0.1);
            const newRadius = radius + Math.sin(elapsedTime * 2 + i) * 0.01;
            
            sparklePositionsAttr.array[i3] = Math.cos(newAngle) * newRadius;
            sparklePositionsAttr.array[i3 + 2] = Math.sin(newAngle) * newRadius;
            
            // Gentle vertical bobbing
            sparklePositionsAttr.array[i3 + 1] += Math.sin(elapsedTime * 3 + i * 2) * 0.005;
            
            // Pulsing size
            sparkleSizesAttr.array[i] = sparkleSizes[i] * (0.8 + Math.sin(elapsedTime * 5 + i) * 0.2);
        }
        
        sparklePositionsAttr.needsUpdate = true;
        sparkleSizesAttr.needsUpdate = true;
        
        // Render the scene
        renderer.render(scene, camera);
        
        // Call animate again on the next frame
        requestAnimationFrame(animate);
    };
    
    // Start animation
    animate();
};

// Function to setup the background canvas for the entire page
const setupPageBackground = () => {
    // Check if we already have a canvas
    let canvas = document.getElementById('bg-canvas');
    
    // If no canvas exists, create one
    if (!canvas) {
        canvas = document.createElement('canvas');
        canvas.id = 'bg-canvas';
        
        // Set canvas styles for fullscreen background
        canvas.style.position = 'fixed';
        canvas.style.top = '0';
        canvas.style.left = '0';
        canvas.style.width = '100%';
        canvas.style.height = '100%';
        canvas.style.zIndex = '-1';
        canvas.style.pointerEvents = 'none'; // Allow clicks to pass through
    }
    
    // Add the canvas to the body as a fixed background
    if (canvas.parentElement !== document.body) {
        document.body.appendChild(canvas);
    }
    
    return canvas;
};

// Add CSS to make content readable over the background
const addBackgroundCSS = () => {
    // Create a style element if it doesn't exist
    let style = document.getElementById('background-styles');
    if (!style) {
        style = document.createElement('style');
        style.id = 'background-styles';
        document.head.appendChild(style);
        
        // Add CSS rules
        style.textContent = `
            body {
                background-color: #000000 !important;
                position: relative;
                z-index: 1;
                color: #fff;
            }
            
            main, article, section, .content, .container {
                position: relative;
                z-index: 1;
                background-color: rgba(0, 10, 30, 0.7);
                padding: 20px;
                border-radius: 5px;
            }
            
            h1, h2, h3, h4, h5, h6 {
                color: #ffffff;
                text-shadow: 0 0 10px rgba(100, 180, 255, 0.5);
            }
            
            a {
                color: #5CEFFF;
                text-shadow: 0 0 5px rgba(92, 239, 255, 0.5);
            }
            
            /* Style adjustments for text contrast */
            p, li, span, div {
                text-shadow: 0 0 5px rgba(0, 0, 0, 0.9);
            }
            
            /* Add a subtle background to text containers */
            article, .content, .container, .card, .post {
                box-shadow: 0 0 20px rgba(100, 180, 255, 0.2);
                backdrop-filter: blur(5px);
                -webkit-backdrop-filter: blur(5px);
                margin-bottom: 20px;
                border: 1px solid rgba(100, 180, 255, 0.2);
            }
            
            /* Style form elements */
            input, textarea, select, button {
                background-color: rgba(20, 30, 60, 0.8);
                border: 1px solid rgba(100, 180, 255, 0.5);
                color: #fff;
            }
            
            button, .button, input[type="submit"] {
                background-color: rgba(0, 120, 180, 0.7);
                color: white;
                border: 1px solid rgba(100, 200, 255, 0.7);
                text-shadow: 0 0 3px rgba(0, 0, 0, 0.5);
            }
        `;
    }
};

// Initialize on DOM load
document.addEventListener('DOMContentLoaded', () => {
    setupPageBackground();
    addBackgroundCSS();
    initZeldaFujiBackground();
    
    // Add a mutation observer to ensure the background works on dynamically loaded pages
    const observer = new MutationObserver((mutations) => {
        let needsReattach = false;
        
        mutations.forEach(mutation => {
            if (mutation.type === 'childList') {
                // Check if our canvas was removed
                const canvas = document.getElementById('bg-canvas');
                if (!canvas || !document.body.contains(canvas)) {
                    needsReattach = true;
                }
            }
        });
        
        if (needsReattach) {
            setupPageBackground();
            initZeldaFujiBackground();
        }
    });
    
    // Start observing the document body for changes
    observer.observe(document.body, {
        childList: true,
        subtree: true
    });
});