---
// Network3D.astro - Visualizes the Agentic Network connections
---
<div id="network-canvas-container"></div>

<style>
#network-canvas-container {
    position: fixed;
    top: 0;
    left: 0;
    width: 100vw;
    height: 100vh;
    z-index: -1;
    pointer-events: none;
    opacity: 0.6;
}
</style>

<script>
    import * as THREE from 'three';

    const container = document.getElementById('network-canvas-container');
    if (container) {
        const scene = new THREE.Scene();
        const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
        const renderer = new THREE.WebGLRenderer({ alpha: true, antialias: true });
        
        renderer.setSize(window.innerWidth, window.innerHeight);
        renderer.setPixelRatio(window.devicePixelRatio);
        container.appendChild(renderer.domElement);

        // Kipinän brändivärit
        const palette = [
            new THREE.Color(0x58a6ff), // Sininen
            new THREE.Color(0xff6b00), // Oranssi
            new THREE.Color(0x2ea043), // Vihreä
            new THREE.Color(0xd29922), // Keltainen
            new THREE.Color(0x8b949e)  // Harmaa
        ];

        // 1. Luodaan perusnoodit (partikkelit)
        const geometry = new THREE.BufferGeometry();
        const particlesCount = 120;
        const posArray = new Float32Array(particlesCount * 3);
        const colorArray = new Float32Array(particlesCount * 3);
        
        for (let i = 0; i < particlesCount; i++) {
            // Levitä pallomaisesti
            posArray[i*3] = (Math.random() - 0.5) * 12;
            posArray[i*3+1] = (Math.random() - 0.5) * 12;
            posArray[i*3+2] = (Math.random() - 0.5) * 12;

            // Valitse satunnainen väri paletista
            const color = palette[Math.floor(Math.random() * palette.length)];
            colorArray[i*3] = color.r;
            colorArray[i*3+1] = color.g;
            colorArray[i*3+2] = color.b;
        }
        
        geometry.setAttribute('position', new THREE.BufferAttribute(posArray, 3));
        geometry.setAttribute('color', new THREE.BufferAttribute(colorArray, 3));
        
        const material = new THREE.PointsMaterial({
            size: 0.08,
            vertexColors: true,
            transparent: true,
            opacity: 0.8
        });
        
        const particlesMesh = new THREE.Points(geometry, material);
        scene.add(particlesMesh);
        
        // 2. Yhdistävät viivat (vain visualisointiin, himmeät)
        const lineMaterial = new THREE.LineBasicMaterial({ 
            vertexColors: true, 
            transparent: true, 
            opacity: 0.15,
            blending: THREE.AdditiveBlending 
        });
        const lineGeometry = new THREE.BufferGeometry();
        lineGeometry.setAttribute('position', new THREE.BufferAttribute(posArray, 3));
        lineGeometry.setAttribute('color', new THREE.BufferAttribute(colorArray, 3));
        const linesMesh = new THREE.LineSegments(lineGeometry, lineMaterial);
        particlesMesh.add(linesMesh);

        // 3. Räjähdykset ja kipinät (Sparks)
        const maxSparks = 1000;
        const sparkGeometry = new THREE.BufferGeometry();
        const sparkPositions = new Float32Array(maxSparks * 3);
        const sparkColors = new Float32Array(maxSparks * 3);
        const sparkVelocities = new Float32Array(maxSparks * 3);
        const sparkLifetimes = new Float32Array(maxSparks);

        // Piilota aluksi kaikki kipinät kauas
        for(let i=0; i<maxSparks*3; i++) sparkPositions[i] = 1000;

        sparkGeometry.setAttribute('position', new THREE.BufferAttribute(sparkPositions, 3));
        sparkGeometry.setAttribute('color', new THREE.BufferAttribute(sparkColors, 3));

        const sparkMaterial = new THREE.PointsMaterial({
            size: 0.04,
            vertexColors: true,
            transparent: true,
            opacity: 1.0,
            blending: THREE.AdditiveBlending
        });
        const sparksMesh = new THREE.Points(sparkGeometry, sparkMaterial);
        particlesMesh.add(sparksMesh); // Lisätään pääverkon sisään jotta pyörii sen mukana

        camera.position.z = 6;

        function triggerExplosion() {
            // Valitse satunnainen noodisolmu lähtöpisteeksi
            const nodeIdx = Math.floor(Math.random() * particlesCount);
            const nx = posArray[nodeIdx * 3];
            const ny = posArray[nodeIdx * 3 + 1];
            const nz = posArray[nodeIdx * 3 + 2];
            
            const nr = colorArray[nodeIdx * 3];
            const ng = colorArray[nodeIdx * 3 + 1];
            const nb = colorArray[nodeIdx * 3 + 2];
            
            const sparkCount = 15 + Math.random() * 25; // 15-40 kipinää
            let spawned = 0;
            
            for(let i=0; i<maxSparks; i++) {
                if(sparkLifetimes[i] <= 0) {
                    sparkLifetimes[i] = 0.5 + Math.random() * 1.5; // Elinikä 0.5-2sek
                    
                    // Alkusijainti on noodi itse
                    sparkPositions[i*3] = nx;
                    sparkPositions[i*3+1] = ny;
                    sparkPositions[i*3+2] = nz;
                    
                    // Satunnainen lentosuunta ja voima (pallomaisesti)
                    const u = Math.random();
                    const v = Math.random();
                    const theta = u * 2.0 * Math.PI;
                    const phi = Math.acos(2.0 * v - 1.0);
                    const speed = 2.0 + Math.random() * 3.0; // Nopeus
                    
                    sparkVelocities[i*3] = Math.sin(phi) * Math.cos(theta) * speed;
                    sparkVelocities[i*3+1] = Math.sin(phi) * Math.sin(theta) * speed;
                    sparkVelocities[i*3+2] = Math.cos(phi) * speed;
                    
                    // Kipinän väri (noodin väri + satunnaista vaaleutta)
                    sparkColors[i*3] = Math.min(1.0, nr + Math.random() * 0.5);
                    sparkColors[i*3+1] = Math.min(1.0, ng + Math.random() * 0.5);
                    sparkColors[i*3+2] = Math.min(1.0, nb + Math.random() * 0.5);
                    
                    spawned++;
                    if(spawned >= sparkCount) break;
                }
            }
        }

        // 4. Animaatiolooppi
        let lastTime = performance.now();

        function animate(time: number) {
            requestAnimationFrame(animate);
            const dt = (time - lastTime) / 1000; // sekunteja
            lastTime = time;
            if (dt > 0.1) return; // vältä lagipiikkien aiheuttamat hyperhypyt

            const elapsedTime = time / 1000;
            particlesMesh.rotation.y = elapsedTime * 0.05;
            particlesMesh.rotation.x = elapsedTime * 0.02;

            // Arvo satunnaisia räjähdyksiä (n. 1 per sekunti)
            if (Math.random() < 1.0 * dt) {
                triggerExplosion();
            }

            // Päivitä kipinät
            let sparksUpdated = false;
            for(let i=0; i<maxSparks; i++) {
                if(sparkLifetimes[i] > 0) {
                    sparkLifetimes[i] -= dt;
                    if(sparkLifetimes[i] <= 0) {
                        sparkPositions[i*3] = 1000; // Piilota kuollessaan
                    } else {
                        // Liikuta nopeuden mukaan
                        sparkPositions[i*3] += sparkVelocities[i*3] * dt;
                        sparkPositions[i*3+1] += sparkVelocities[i*3+1] * dt;
                        sparkPositions[i*3+2] += sparkVelocities[i*3+2] * dt;
                        
                        // Painovoimaefekti / ilmanvastus
                        sparkVelocities[i*3+1] -= 2.0 * dt; // Painovoima
                        sparkVelocities[i*3] *= 0.98; // Ilmanvastus 
                        sparkVelocities[i*3+1] *= 0.98;
                        sparkVelocities[i*3+2] *= 0.98;
                    }
                    sparksUpdated = true;
                }
            }

            if (sparksUpdated) {
                sparkGeometry.attributes.position.needsUpdate = true;
                sparkGeometry.attributes.color.needsUpdate = true;
            }

            renderer.render(scene, camera);
        }
        
        requestAnimationFrame((time) => { lastTime = time; requestAnimationFrame(animate); });

        // Pakotettu uudelleenkokoyritys
        window.addEventListener('resize', () => {
            camera.aspect = window.innerWidth / window.innerHeight;
            camera.updateProjectionMatrix();
            renderer.setSize(window.innerWidth, window.innerHeight);
        });
    }
</script>
