/**
 * Galaxy Background Animation
 * A Three.js based animated galaxy simulation for website backgrounds
 */
class GalaxyBackground {
    constructor(containerId = 'background-container') {
        this.containerId = containerId;
        this.setup();
        this.createScene();
        this.createGalaxy();
        this.clock = new THREE.Clock();
        this.animate();
        
        // Handle window resize
        window.addEventListener('resize', () => this.onWindowResize(), false);
    }
    
    setup() {
        // Create container if it doesn't exist
        if (!document.getElementById(this.containerId)) {
            const container = document.createElement('div');
            container.id = this.containerId;
            container.style.position = 'fixed';
            container.style.top = '0';
            container.style.left = '0';
            container.style.width = '100%';
            container.style.height = '100%';
            container.style.zIndex = '-1';
            container.style.overflow = 'hidden';
            document.body.prepend(container);
        }
        
        // Setup Three.js scene, camera, and renderer
        this.scene = new THREE.Scene();
        this.camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
        this.renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
        this.renderer.setSize(window.innerWidth, window.innerHeight);
        this.renderer.setClearColor(0x000000, 1);
        document.getElementById(this.containerId).appendChild(this.renderer.domElement);
        
        // Setup camera position
        this.camera.position.set(0, 7, 15);
        this.camera.lookAt(0, 0, 0);
        
        // Container for galaxy elements
        this.galaxyGroup = new THREE.Group();
        this.scene.add(this.galaxyGroup);
        
        // Store celestial entities
        this.entities = [];
        
        // Auto rotation settings
        this.autoRotate = true;
        this.autoRotateSpeed = 0.05;
    }
    
    createScene() {
        // Add ambient light
        const ambientLight = new THREE.AmbientLight(0xffffff, 0.3);
        this.scene.add(ambientLight);
        
        // Add point light
        const pointLight = new THREE.PointLight(0xffffff, 1);
        pointLight.position.set(5, 5, 5);
        this.scene.add(pointLight);
    }
    
    createGalaxy() {
        this.createDustDisk();
        this.createBackgroundStars();
        this.createAsteroidBelt();
        this.createCelestialBodies();
    }
    
    createDustDisk() {
        const particleCount = 15000;
        const geometry = new THREE.BufferGeometry();
        const positions = new Float32Array(particleCount * 3);
        const colors = new Float32Array(particleCount * 3);
        
        for (let i = 0; i < particleCount; i++) {
            const distance = Math.random() * 10;
            const theta = Math.random() * Math.PI * 2;
            positions[i * 3] = distance * Math.cos(theta);
            positions[i * 3 + 1] = (Math.random() - 0.5) * 0.1;
            positions[i * 3 + 2] = distance * Math.sin(theta);
            
            const color = new THREE.Color();
            color.setHSL(0.6, 1.0, Math.random() * 0.2 + 0.8);
            colors[i * 3] = color.r;
            colors[i * 3 + 1] = color.g;
            colors[i * 3 + 2] = color.b;
        }
        
        geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
        geometry.setAttribute('color', new THREE.BufferAttribute(colors, 3));
        
        const material = new THREE.PointsMaterial({
            size: 0.05,
            vertexColors: true,
            transparent: true,
            opacity: 0.8
        });
        
        this.dustDisk = new THREE.Points(geometry, material);
        this.galaxyGroup.add(this.dustDisk);
    }
    
    createBackgroundStars() {
        const starCount = 7000;
        const geometry = new THREE.BufferGeometry();
        const positions = new Float32Array(starCount * 3);
        
        for (let i = 0; i < starCount; i++) {
            const theta = Math.random() * Math.PI * 2;
            const phi = Math.acos(Math.random() * 2 - 1);
            const radius = 50 + Math.random() * 50;
            positions[i * 3] = radius * Math.sin(phi) * Math.cos(theta);
            positions[i * 3 + 1] = radius * Math.sin(phi) * Math.sin(theta);
            positions[i * 3 + 2] = radius * Math.cos(phi);
        }
        
        geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
        
        const material = new THREE.PointsMaterial({
            size: 0.05,
            color: 0xffffff,
            transparent: true,
            opacity: 0.8
        });
        
        this.backgroundStars = new THREE.Points(geometry, material);
        this.scene.add(this.backgroundStars);
    }
    
    createAsteroidBelt() {
        const asteroidCount = 200;
        const asteroidGeometry = new THREE.SphereGeometry(0.05, 8, 8);
        const asteroidMaterial = new THREE.MeshBasicMaterial({ color: 0x8B4513 });
        
        for (let i = 0; i < asteroidCount; i++) {
            const asteroid = new THREE.Mesh(asteroidGeometry, asteroidMaterial);
            const angle = (i / asteroidCount) * Math.PI * 2;
            const radius = 12 + Math.random() * 2;
            
            asteroid.position.set(
                radius * Math.cos(angle),
                (Math.random() - 0.5) * 0.5,
                radius * Math.sin(angle)
            );
            
            this.galaxyGroup.add(asteroid);
        }
    }
    
    createCelestialBodies() {
        // Create a central star
        this.createStar(0, 0, 0, 0.3, 0xffdd88);
        
        // Create various planets
        this.createPlanet(3, 0.1, 0x3498db, 0.15);
        this.createPlanet(5, 0.1, 0xe74c3c, 0.1);
        this.createPlanet(7, 0.12, 0x2ecc71, 0.08);
        this.createRingedPlanet(9, 0.11, 0xf1c40f, 0xc39bd3, 0.06);
        
        // Create a few comets
        this.createComet(4, 0.05, 0x87CEEB, 0.3);
        this.createComet(8, 0.05, 0x00FFFF, 0.4);
        
        // Create lightning planet
        this.createLightningPlanet(6, 0.09, 0x9b59b6, 0xFFFFFF, 0.12);
        
        // Create a quasar
        this.createQuasar(11, 0.15, 0x3498db, 0.02);
    }
    
    createStar(radius, size, color, orbitSpeed = 0) {
        const geometry = new THREE.SphereGeometry(size, 32, 32);
        const material = new THREE.MeshBasicMaterial({ color: color });
        const star = new THREE.Mesh(geometry, material);
        
        // Create glow effect
        const glowGeometry = new THREE.SphereGeometry(size * 1.2, 32, 32);
        const glowMaterial = new THREE.ShaderMaterial({
            uniforms: {
                c: { type: "f", value: 0.1 },
                p: { type: "f", value: 1.2 },
                glowColor: { type: "c", value: new THREE.Color(color) }
            },
            vertexShader: `
                varying vec3 vNormal;
                void main() 
                {
                    vNormal = normalize(normalMatrix * normal);
                    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
                }
            `,
            fragmentShader: `
                uniform vec3 glowColor;
                uniform float c;
                uniform float p;
                varying vec3 vNormal;
                void main() 
                {
                    float intensity = pow(c - dot(vNormal, vec3(0.0, 0.0, 1.0)), p);
                    gl_FragColor = vec4(glowColor, 1.0) * intensity;
                }
            `,
            side: THREE.FrontSide,
            blending: THREE.AdditiveBlending,
            transparent: true
        });
        
        const glow = new THREE.Mesh(glowGeometry, glowMaterial);
        star.add(glow);
        
        const angle = Math.random() * Math.PI * 2;
        star.position.x = radius * Math.cos(angle);
        star.position.z = radius * Math.sin(angle);
        
        this.galaxyGroup.add(star);
        
        this.entities.push({
            id: Date.now().toString() + Math.random(),
            object: star,
            type: 'star',
            radius: radius,
            angle: angle,
            orbitSpeed: orbitSpeed,
            glow: glow
        });
    }
    
    createPlanet(radius, size, color, orbitSpeed) {
        const geometry = new THREE.SphereGeometry(size, 32, 32);
        const material = new THREE.MeshBasicMaterial({ color: color });
        const planet = new THREE.Mesh(geometry, material);
        
        const angle = Math.random() * Math.PI * 2;
        planet.position.x = radius * Math.cos(angle);
        planet.position.z = radius * Math.sin(angle);
        
        this.galaxyGroup.add(planet);
        
        this.entities.push({
            id: Date.now().toString() + Math.random(),
            object: planet,
            type: 'planet',
            radius: radius,
            angle: angle,
            orbitSpeed: orbitSpeed
        });
    }
    
    createRingedPlanet(radius, size, color, ringColor, orbitSpeed) {
        const planetGeometry = new THREE.SphereGeometry(size, 32, 32);
        const planetMaterial = new THREE.MeshBasicMaterial({ color: color });
        const planet = new THREE.Mesh(planetGeometry, planetMaterial);
        
        const ringGeometry = new THREE.RingGeometry(size * 1.5, size * 2, 32);
        const ringMaterial = new THREE.MeshBasicMaterial({ color: ringColor, side: THREE.DoubleSide });
        const ring = new THREE.Mesh(ringGeometry, ringMaterial);
        ring.rotation.x = Math.PI / 2;
        
        const planetGroup = new THREE.Group();
        planetGroup.add(planet);
        planetGroup.add(ring);
        
        const angle = Math.random() * Math.PI * 2;
        planetGroup.position.x = radius * Math.cos(angle);
        planetGroup.position.z = radius * Math.sin(angle);
        
        this.galaxyGroup.add(planetGroup);
        
        this.entities.push({
            id: Date.now().toString() + Math.random(),
            object: planetGroup,
            type: 'ringedPlanet',
            ring: ring,
            radius: radius,
            angle: angle,
            orbitSpeed: orbitSpeed
        });
    }
    
    createComet(radius, size, color, orbitSpeed) {
        const geometry = new THREE.SphereGeometry(size, 32, 32);
        const material = new THREE.MeshBasicMaterial({ color: color });
        const comet = new THREE.Mesh(geometry, material);
        
        const angle = Math.random() * Math.PI * 2;
        comet.position.x = radius * Math.cos(angle);
        comet.position.z = radius * Math.sin(angle);
        
        this.galaxyGroup.add(comet);
        
        const cometData = {
            id: Date.now().toString() + Math.random(),
            object: comet,
            type: 'comet',
            color: color,
            radius: radius,
            angle: angle,
            orbitSpeed: orbitSpeed
        };
        
        this.entities.push(cometData);
        this.updateCometTail(cometData);
        this.updateCometGlow(cometData);
    }
    
    createLightningPlanet(radius, size, color, lightningColor, orbitSpeed) {
        const geometry = new THREE.SphereGeometry(size, 32, 32);
        const material = new THREE.MeshBasicMaterial({ color: color });
        const planet = new THREE.Mesh(geometry, material);
        
        const angle = Math.random() * Math.PI * 2;
        planet.position.x = radius * Math.cos(angle);
        planet.position.z = radius * Math.sin(angle);
        
        this.galaxyGroup.add(planet);
        
        const planetData = {
            id: Date.now().toString() + Math.random(),
            object: planet,
            type: 'lightningPlanet',
            lightningColor: lightningColor,
            radius: radius,
            angle: angle,
            orbitSpeed: orbitSpeed,
            lightningTimer: 0
        };
        
        this.entities.push(planetData);
        this.updateLightningPlanet(planetData, 0);
    }
    
    createQuasar(radius, size, color, orbitSpeed) {
        const geometry = new THREE.SphereGeometry(size, 32, 32);
        const material = new THREE.MeshBasicMaterial({ color: color });
        const quasar = new THREE.Mesh(geometry, material);
        
        const angle = Math.random() * Math.PI * 2;
        quasar.position.x = radius * Math.cos(angle);
        quasar.position.z = radius * Math.sin(angle);
        
        this.galaxyGroup.add(quasar);
        
        const quasarData = {
            id: Date.now().toString() + Math.random(),
            object: quasar,
            type: 'quasar',
            color: color,
            radius: radius,
            angle: angle,
            orbitSpeed: orbitSpeed
        };
        
        this.entities.push(quasarData);
        this.updateQuasar(quasarData, 0);
    }
    
    animate() {
        requestAnimationFrame(() => this.animate());
        
        const deltaTime = this.clock.getDelta();
        
        // Update various elements
        this.updateDustDisk(deltaTime);
        this.updateEntities(deltaTime);
        this.rotateBackgroundStars(deltaTime);
        
        // Auto-rotate the galaxy
        if (this.autoRotate) {
            this.galaxyGroup.rotation.y += this.autoRotateSpeed * deltaTime;
        }
        
        this.renderer.render(this.scene, this.camera);
    }
    
    updateDustDisk(deltaTime) {
        const positions = this.dustDisk.geometry.attributes.position.array;
        
        for (let i = 0; i < positions.length; i += 3) {
            const x = positions[i];
            const z = positions[i + 2];
            const distance = Math.sqrt(x * x + z * z);
            const angle = Math.atan2(z, x) + deltaTime * (1 / (distance + 0.1)) * 0.5;
            
            positions[i] = distance * Math.cos(angle);
            positions[i + 2] = distance * Math.sin(angle);
        }
        
        this.dustDisk.geometry.attributes.position.needsUpdate = true;
    }
    
    updateEntities(deltaTime) {
        this.entities.forEach(entity => {
            if (entity.type === 'planet' || entity.type === 'ringedPlanet') {
                // Update planet positions
                const radius = entity.radius;
                const angle = entity.angle + entity.orbitSpeed * deltaTime;
                entity.angle = angle;
                entity.object.position.x = radius * Math.cos(angle);
                entity.object.position.z = radius * Math.sin(angle);
                
                // Add fluid dynamics effect to dust particles near planets
                this.flowDustAroundEntity(entity.object.position, 0.5);
            } else if (entity.type === 'star') {
                // Add fluid dynamics effect to dust particles near stars
                this.flowDustAroundEntity(entity.object.position, 1);
            } else if (entity.type === 'comet') {
                this.updateComet(entity, deltaTime);
            } else if (entity.type === 'lightningPlanet') {
                this.updateLightningPlanet(entity, deltaTime);
            } else if (entity.type === 'quasar') {
                this.updateQuasar(entity, deltaTime);
            }
        });
    }
    
    updateComet(comet, deltaTime) {
        comet.angle += comet.orbitSpeed * deltaTime;
        const x = comet.radius * Math.cos(comet.angle);
        const z = comet.radius * Math.sin(comet.angle);
        comet.object.position.set(x, 0, z);
        
        this.updateCometTail(comet);
    }
    
    updateCometTail(comet) {
        if (!comet.tail) {
            const tailGeometry = new THREE.BufferGeometry();
            const tailMaterial = new THREE.PointsMaterial({
                size: 0.05,
                color: comet.color,
                transparent: true,
                opacity: 0.6,
                blending: THREE.AdditiveBlending
            });
            
            comet.tail = new THREE.Points(tailGeometry, tailMaterial);
            this.galaxyGroup.add(comet.tail);
        }
        
        const tailLength = 2;
        const particleCount = 100;
        const positions = new Float32Array(particleCount * 3);
        
        for (let i = 0; i < particleCount; i++) {
            const t = i / particleCount;
            const x = comet.object.position.x - t * tailLength * Math.cos(comet.angle);
            const y = comet.object.position.y + (Math.random() - 0.5) * 0.1;
            const z = comet.object.position.z - t * tailLength * Math.sin(comet.angle);
            
            positions[i * 3] = x;
            positions[i * 3 + 1] = y;
            positions[i * 3 + 2] = z;
        }
        
        comet.tail.geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
        comet.tail.geometry.attributes.position.needsUpdate = true;
    }
    
    updateCometGlow(comet) {
        if (!comet.glow) {
            const glowGeometry = new THREE.SphereGeometry(0.15, 32, 32);
            const glowMaterial = new THREE.ShaderMaterial({
                uniforms: {
                    c: { type: "f", value: 0.1 },
                    p: { type: "f", value: 1.2 },
                    glowColor: { type: "c", value: new THREE.Color(comet.color) }
                },
                vertexShader: `
                    varying vec3 vNormal;
                    void main() 
                    {
                        vNormal = normalize(normalMatrix * normal);
                        gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
                    }
                `,
                fragmentShader: `
                    uniform vec3 glowColor;
                    uniform float c;
                    uniform float p;
                    varying vec3 vNormal;
                    void main() 
                    {
                        float intensity = pow(c - dot(vNormal, vec3(0.0, 0.0, 1.0)), p);
                        gl_FragColor = vec4(glowColor, 1.0) * intensity;
                    }
                `,
                side: THREE.FrontSide,
                blending: THREE.AdditiveBlending,
                transparent: true
            });
            
            comet.glow = new THREE.Mesh(glowGeometry, glowMaterial);
            comet.object.add(comet.glow);
        }
    }
    
    updateLightningPlanet(planet, deltaTime) {
        if (!planet.lightningSystem) {
            planet.lightningSystem = new THREE.Group();
            planet.object.add(planet.lightningSystem);
            planet.lightningTimer = 0;
        }
        
        planet.lightningTimer -= deltaTime;
        if (planet.lightningTimer <= 0) {
            this.createLightning(planet);
            planet.lightningTimer = Math.random() * 0.5 + 0.1; // Random time between 0.1 and 0.6 seconds
        }
    }
    
    createLightning(planet) {
        const lightningGeometry = new THREE.BufferGeometry();
        const lightningMaterial = new THREE.LineBasicMaterial({ color: planet.lightningColor });
        const points = [];
        
        const startAngle = Math.random() * Math.PI * 2;
        const endAngle = startAngle + (Math.random() * Math.PI / 2 - Math.PI / 4);
        const radius = 0.15; // Slightly larger than the planet
        
        points.push(new THREE.Vector3(
            Math.cos(startAngle) * radius,
            Math.sin(startAngle) * radius,
            0
        ));
        
        for (let i = 0; i < 5; i++) {
            const t = (i + 1) / 6;
            const angle = startAngle + (endAngle - startAngle) * t;
            points.push(new THREE.Vector3(
                Math.cos(angle) * radius + (Math.random() - 0.5) * 0.05,
                Math.sin(angle) * radius + (Math.random() - 0.5) * 0.05,
                (Math.random() - 0.5) * 0.05
            ));
        }
        
        points.push(new THREE.Vector3(
            Math.cos(endAngle) * radius,
            Math.sin(endAngle) * radius,
            0
        ));
        
        lightningGeometry.setFromPoints(points);
        const lightning = new THREE.Line(lightningGeometry, lightningMaterial);
        planet.lightningSystem.add(lightning);
        
        setTimeout(() => {
            planet.lightningSystem.remove(lightning);
            lightning.geometry.dispose();
            lightning.material.dispose();
        }, 100); // Remove lightning after 100ms
    }
    
    updateQuasar(quasar, deltaTime) {
        if (!quasar.shaft) {
            const shaftGeometry = new THREE.CylinderGeometry(0.05, 0.05, 10, 32);
            const shaftMaterial = new THREE.MeshBasicMaterial({ color: quasar.color, transparent: true, opacity: 0.7 });
            
            quasar.shaft = new THREE.Mesh(shaftGeometry, shaftMaterial);
            quasar.shaft.rotation.x = Math.PI / 2;
            quasar.object.add(quasar.shaft);
            
            const particleCount = 1000;
            const particles = new THREE.BufferGeometry();
            const positions = new Float32Array(particleCount * 3);
            
            for (let i = 0; i < particleCount; i++) {
                const t = Math.random();
                const angle = Math.random() * Math.PI * 2;
                const radius = 0.05 + t * 0.05;
                positions[i * 3] = Math.cos(angle) * radius;
                positions[i * 3 + 1] = (Math.random() - 0.5) * 10;
                positions[i * 3 + 2] = Math.sin(angle) * radius;
            }
            
            particles.setAttribute('position', new THREE.BufferAttribute(positions, 3));
            const particleMaterial = new THREE.PointsMaterial({ color: quasar.color, size: 0.02 });
            quasar.particles = new THREE.Points(particles, particleMaterial);
            quasar.object.add(quasar.particles);
        }
        
        quasar.shaft.rotation.z += deltaTime;
        const positions = quasar.particles.geometry.attributes.position.array;
        
        for (let i = 0; i < positions.length; i += 3) {
            positions[i + 1] += deltaTime * (Math.random() + 0.5); // Move particles along the shaft
            if (positions[i + 1] > 5) positions[i + 1] = -5; // Reset particles at the end of the shaft
        }
        
        quasar.particles.geometry.attributes.position.needsUpdate = true;
    }
    
    flowDustAroundEntity(position, radius) {
        const positions = this.dustDisk.geometry.attributes.position.array;
        
        for (let i = 0; i < positions.length; i += 3) {
            const dustX = positions[i];
            const dustZ = positions[i + 2];
            const dx = dustX - position.x;
            const dz = dustZ - position.z;
            const distance = Math.sqrt(dx * dx + dz * dz);
            
            if (distance < radius) {
                const angle = Math.atan2(dz, dx);
                const tangentialSpeed = 0.1 * (1 - distance / radius);
                const newAngle = angle + tangentialSpeed;
                const newDistance = Math.max(distance, radius * 0.8);
                
                positions[i] = position.x + newDistance * Math.cos(newAngle);
                positions[i + 2] = position.z + newDistance * Math.sin(newAngle);
            }
        }
        
        this.dustDisk.geometry.attributes.position.needsUpdate = true;
    }
    
    rotateBackgroundStars(deltaTime) {
        this.backgroundStars.rotation.y += 0.01 * deltaTime;
    }
    
    onWindowResize() {
        this.camera.aspect = window.innerWidth / window.innerHeight;
        this.camera.updateProjectionMatrix();
        this.renderer.setSize(window.innerWidth, window.innerHeight);
    }
    
    // Public methods for controlling the background
    setAutoRotate(enabled) {
        this.autoRotate = enabled;
    }
    
    setRotationSpeed(speed) {
        this.autoRotateSpeed = speed;
    }
    
    setCameraPosition(x, y, z) {
        this.camera.position.set(x, y, z);
        this.camera.lookAt(0, 0, 0);
    }
    
    setBackgroundColor(color) {
        this.renderer.setClearColor(color);
    }
    
    dispose() {
        window.removeEventListener('resize', this.onWindowResize);
        this.renderer.dispose();
        document.getElementById(this.containerId).removeChild(this.renderer.domElement);
    }
}

// Initialize the galaxy background when the page loads
document.addEventListener('DOMContentLoaded', function() {
    // Check if Three.js is loaded
    if (typeof THREE === 'undefined') {
        console.error('Three.js is required for GalaxyBackground. Please include it in your HTML.');
        
        // Create a script element to load Three.js
        const script = document.createElement('script');
        script.src = 'https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js';
        script.onload = function() {
            // Initialize the galaxy background after Three.js is loaded
            window.galaxyBackground = new GalaxyBackground();
        };
        document.head.appendChild(script);
    } else {
        // If Three.js is already loaded, initialize the galaxy background
        window.galaxyBackground = new GalaxyBackground();
    }
});
