import React, { useEffect, useRef, useState } from 'react';
import { Link } from 'react-router-dom';
import * as THREE from 'three';
import './SwordStream.css';

const SwordStream = () => {
    const containerRef = useRef(null);
    const requestRef = useRef();
    const [mode, setMode] = useState('HOVER'); // HOVER, ORBIT

    useEffect(() => {
        if (!containerRef.current) return;

        const COUNT = 1500;
        const SWORD_COLOR = 0x44aadd;
        const SWORD_EMISSIVE = 0x112244;

        const rand = (min, max) => Math.random() * (max - min) + min;

        const width = containerRef.current.clientWidth;
        const height = containerRef.current.clientHeight;

        const scene = new THREE.Scene();
        scene.fog = new THREE.FogExp2(0x050505, 0.002);

        const camera = new THREE.PerspectiveCamera(75, width / height, 0.1, 1000);
        camera.position.z = 80;

        const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
        renderer.setSize(width, height);
        renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
        renderer.toneMapping = THREE.ACESFilmicToneMapping;
        containerRef.current.appendChild(renderer.domElement);

        const ambientLight = new THREE.AmbientLight(0x404040);
        scene.add(ambientLight);

        const pointLight = new THREE.PointLight(SWORD_COLOR, 2, 100);
        scene.add(pointLight);

        const geometry = new THREE.CylinderGeometry(0.1, 0.4, 4, 8);
        geometry.rotateX(Math.PI / 2);

        const material = new THREE.MeshPhongMaterial({
            color: SWORD_COLOR,
            emissive: SWORD_EMISSIVE,
            shininess: 100,
            flatShading: true,
        });

        const mesh = new THREE.InstancedMesh(geometry, material, COUNT);
        scene.add(mesh);

        const dummy = new THREE.Object3D();
        const particles = [];

        for (let i = 0; i < COUNT; i++) {
            particles.push({
                pos: new THREE.Vector3(rand(-100, 100), rand(-100, 100), rand(-50, 50)),
                vel: new THREE.Vector3(),
                acc: new THREE.Vector3(),
                angle: rand(0, Math.PI * 2),
                radius: rand(15, 30),
                speed: rand(0.02, 0.05),
                offset: new THREE.Vector3(rand(-5, 5), rand(-5, 5), rand(-5, 5)),
            });
        }

        const mouse = new THREE.Vector3();
        const target = new THREE.Vector3();
        const mousePlane = new THREE.Plane(new THREE.Vector3(0, 0, 1), 0);
        const raycaster = new THREE.Raycaster();

        let isMouseDown = false;
        let time = 0;

        const handleMouseMove = (e) => {
            const rect = renderer.domElement.getBoundingClientRect();
            const x = ((e.clientX - rect.left) / rect.width) * 2 - 1;
            const y = -((e.clientY - rect.top) / rect.height) * 2 + 1;

            raycaster.setFromCamera(new THREE.Vector2(x, y), camera);
            raycaster.ray.intersectPlane(mousePlane, mouse);

            pointLight.position.copy(mouse);
            pointLight.position.z = 20;
        };

        const handleMouseDown = () => { isMouseDown = true; setMode('ORBIT'); };
        const handleMouseUp = () => { isMouseDown = false; setMode('HOVER'); };

        window.addEventListener('mousemove', handleMouseMove);
        window.addEventListener('mousedown', handleMouseDown);
        window.addEventListener('mouseup', handleMouseUp);

        const animate = () => {
            requestRef.current = requestAnimationFrame(animate);
            time += 0.01;

            for (let i = 0; i < COUNT; i++) {
                const p = particles[i];

                if (isMouseDown) {
                    p.angle += p.speed + 0.02;
                    const orbitX = mouse.x + Math.cos(p.angle + time) * p.radius;
                    const orbitY = mouse.y + Math.sin(p.angle + time) * p.radius;
                    const orbitZ = Math.sin(p.angle * 2 + time) * 10;
                    target.set(orbitX, orbitY, orbitZ);
                    p.acc.subVectors(target, p.pos).multiplyScalar(0.08);
                } else {
                    const noiseX = Math.sin(time + i * 0.1) * 5;
                    const noiseY = Math.cos(time + i * 0.1) * 5;
                    target.copy(mouse).add(p.offset).add(new THREE.Vector3(noiseX, noiseY, 0));
                    p.acc.subVectors(target, p.pos).multiplyScalar(0.008);
                }

                p.vel.add(p.acc);
                p.vel.multiplyScalar(isMouseDown ? 0.90 : 0.94);
                p.pos.add(p.vel);

                dummy.position.copy(p.pos);

                const lookPos = new THREE.Vector3().copy(p.pos).add(p.vel.clone().multiplyScalar(5));
                if (p.vel.lengthSq() > 0.01) {
                    dummy.lookAt(lookPos);
                }

                const speedScale = 1 + Math.min(p.vel.length(), 2) * 0.5;
                dummy.scale.set(1, 1, speedScale);

                dummy.updateMatrix();
                mesh.setMatrixAt(i, dummy.matrix);
            }

            mesh.instanceMatrix.needsUpdate = true;
            renderer.render(scene, camera);
        };

        animate();

        const handleResize = () => {
            if (!containerRef.current) return;
            const newWidth = containerRef.current.clientWidth;
            const newHeight = containerRef.current.clientHeight;
            camera.aspect = newWidth / newHeight;
            camera.updateProjectionMatrix();
            renderer.setSize(newWidth, newHeight);
        };

        window.addEventListener('resize', handleResize);

        return () => {
            window.removeEventListener('mousemove', handleMouseMove);
            window.removeEventListener('mousedown', handleMouseDown);
            window.removeEventListener('mouseup', handleMouseUp);
            window.removeEventListener('resize', handleResize);
            cancelAnimationFrame(requestRef.current);
            if (containerRef.current && renderer.domElement) {
                containerRef.current.removeChild(renderer.domElement);
            }
            geometry.dispose();
            material.dispose();
            renderer.dispose();
        };
    }, []);

    return (
        <div className="sword-stream" ref={containerRef}>
            <div className="sword-stream__overlay">
                <Link to="/lab" className="sword-stream__back">← Lab</Link>
                <h2>Sword Stream</h2>
                <div className="sword-stream__mode">
                    MODE: <span>{mode}</span>
                </div>
                <p>
                    <strong>Move</strong> to Guide &nbsp;|&nbsp;
                    <strong>Click &amp; Hold</strong> to Orbit &amp; Charge
                </p>
            </div>
        </div>
    );
};

export default SwordStream;
