import * as THREE from 'three';
import { useRef, useState, useEffect } from 'react';
import { Sphere, TransformControls } from '@react-three/drei';
import { useIsConnecting, useRenderDistance, useSelectedActionSphere, useSelectedPath, useSimulationPaths } from '../../../store/store';
import { useFrame, useThree } from '@react-three/fiber';
import { useSubModuleStore } from '../../../store/useModuleStore';

interface Path {
    modeluuid: string;
    modelName: string;
    points: {
        uuid: string;
        position: [number, number, number];
        rotation: [number, number, number];
        actions: { uuid: string; name: string; type: string; material: string; delay: number | string; spawnInterval: number | string; isUsed: boolean }[] | [];
        triggers: { uuid: string; name: string; type: string; isUsed: boolean }[] | [];
    }[];
    pathPosition: [number, number, number];
    pathRotation: [number, number, number];
    speed: number;
}

function PathCreation({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObject<THREE.Group> }) {
    const { renderDistance } = useRenderDistance();
    const { setSubModule } = useSubModuleStore();
    const { setSelectedActionSphere, selectedActionSphere } = useSelectedActionSphere();
    const { setSelectedPath } = useSelectedPath();
    const { simulationPaths, setSimulationPaths } = useSimulationPaths();
    const { isConnecting } = useIsConnecting();
    const { camera } = useThree();

    const groupRefs = useRef<{ [key: string]: THREE.Group }>({});
    const sphereRefs = useRef<{ [key: string]: THREE.Mesh }>({});
    const transformRef = useRef<any>(null);
    const [transformMode, setTransformMode] = useState<'translate' | 'rotate' | null>(null);

    useEffect(() => {
        setTransformMode(null);
        const handleKeyDown = (e: KeyboardEvent) => {
            if (!selectedActionSphere) return;
            if (e.key === 'g') {
                setTransformMode(prev => prev === 'translate' ? null : 'translate');
            }
            if (e.key === 'r') {
                setTransformMode(prev => prev === 'rotate' ? null : 'rotate');
            }
        };

        window.addEventListener('keydown', handleKeyDown);
        return () => window.removeEventListener('keydown', handleKeyDown);
    }, [selectedActionSphere]);

    useFrame(() => {
        Object.values(groupRefs.current).forEach(group => {
            if (group) {
                const distance = new THREE.Vector3(...group.position.toArray()).distanceTo(camera.position);
                group.visible = distance <= renderDistance;
            }
        });
    });

    const updateSimulationPaths = () => {
        if (!selectedActionSphere) return;

        const updatedPaths: Path[] = simulationPaths.map((path) => ({
            ...path,
            points: path.points.map((point) =>
                point.uuid === selectedActionSphere.point.uuid
                    ? {
                        ...point,
                        position: [
                            selectedActionSphere.point.position.x,
                            selectedActionSphere.point.position.y,
                            selectedActionSphere.point.position.z,
                        ],
                        rotation: [
                            selectedActionSphere.point.rotation.x,
                            selectedActionSphere.point.rotation.y,
                            selectedActionSphere.point.rotation.z,
                        ]
                    }
                    : point
            ),
        }));

        setSimulationPaths(updatedPaths);
    };


    return (
        <group name='simulation-simulationPaths-group' ref={pathsGroupRef} >
            {simulationPaths.map((path) => {
                const points = path.points.map(point => new THREE.Vector3(...point.position));

                return (
                    <group
                        name={`${path.modeluuid}-event-path`}
                        key={path.modeluuid}
                        ref={el => (groupRefs.current[path.modeluuid] = el!)}
                        position={path.pathPosition}
                        rotation={path.pathRotation}
                        onClick={(e) => {
                            if (isConnecting) return;
                            e.stopPropagation();
                            setSelectedPath({ path, group: groupRefs.current[path.modeluuid] });
                            setSelectedActionSphere(null);
                            setTransformMode(null);
                            setSubModule('mechanics');
                        }}
                        onPointerMissed={() => {
                            setSelectedPath(null);
                            setSubModule('properties');
                        }}
                    >
                        {path.points.map((point, index) => (
                            <Sphere
                                key={point.uuid}
                                uuid={point.uuid}
                                position={point.position}
                                args={[0.15, 32, 32]}
                                name='action-sphere'
                                ref={el => (sphereRefs.current[point.uuid] = el!)}
                                onClick={(e) => {
                                    if (isConnecting) return;
                                    e.stopPropagation();
                                    setSelectedActionSphere({
                                        path,
                                        point: sphereRefs.current[point.uuid]
                                    });
                                    setSubModule('mechanics');
                                    setSelectedPath(null);
                                }}
                                userData={{ point, path }}
                                onPointerMissed={() => {
                                    setSubModule('properties');
                                    setSelectedActionSphere(null)
                                }}
                            >
                                <meshStandardMaterial
                                    color={index === 0 ? 'orange' : index === path.points.length - 1 ? 'blue' : 'green'}
                                />
                            </Sphere>
                        ))}

                        {points.slice(0, -1).map((point, index) => {
                            const nextPoint = points[index + 1];
                            const segmentCurve = new THREE.CatmullRomCurve3([point, nextPoint]);
                            const tubeGeometry = new THREE.TubeGeometry(segmentCurve, 20, 0.1, 16, false);

                            return (
                                <mesh name='event-connection-tube' key={`tube-${index}`} geometry={tubeGeometry}>
                                    <meshStandardMaterial transparent opacity={0.9} color="red" />
                                </mesh>
                            );
                        })}
                    </group>
                );
            })}

            {selectedActionSphere && transformMode && (
                <TransformControls
                    ref={transformRef}
                    object={selectedActionSphere.point}
                    mode={transformMode}
                    onObjectChange={updateSimulationPaths}
                />
            )}
        </group>
    );
}

export default PathCreation;
