import { useEffect, useMemo, useRef, useState } from 'react';
import * as THREE from 'three';
import { useFrame, useThree } from '@react-three/fiber';
import { useActiveLayer, useToolMode, useToggleView } from '../../../../store/builder/store';
import * as Constants from '../../../../types/world/worldConstants';
import { Extrude } from '@react-three/drei';

interface ReferenceAisleProps {
    tempPoints: Point[];
    aisleType: AisleTypes;
    aisleWidth: number;
    aisleColor: AisleColors;
}

function ReferenceAisle({ tempPoints, aisleType, aisleWidth, aisleColor }: Readonly<ReferenceAisleProps>) {
    const { pointer, raycaster, camera } = useThree();
    const { toolMode } = useToolMode();
    const { toggleView } = useToggleView();
    const { activeLayer } = useActiveLayer();
    const plane = new THREE.Plane(new THREE.Vector3(0, 1, 0), 0);

    const [tempAisle, setTempAisle] = useState<Aisle | null>(null);
    const mousePosRef = useRef<THREE.Vector3>(new THREE.Vector3());

    useFrame(() => {
        if (toolMode === "Aisle" && toggleView && tempPoints.length === 1) {
            raycaster.setFromCamera(pointer, camera);
            const intersectionPoint = new THREE.Vector3();
            raycaster.ray.intersectPlane(plane, intersectionPoint);

            if (intersectionPoint) {
                mousePosRef.current.copy(intersectionPoint);

                setTempAisle({
                    uuid: 'temp-aisle',
                    points: [
                        tempPoints[0],
                        {
                            uuid: 'temp-point',
                            position: [mousePosRef.current.x, mousePosRef.current.y, mousePosRef.current.z],
                            layer: activeLayer
                        }
                    ],
                    type: {
                        typeName: 'Aisle',
                        aisleType: aisleType,
                        aisleColor: aisleColor,
                        aisleWidth: aisleWidth
                    }
                });
            }
        } else if (tempAisle !== null) {
            setTempAisle(null);
        }
    });

    useEffect(() => {
        setTempAisle(null);
    }, [toolMode, toggleView, tempPoints.length, aisleType, aisleWidth, aisleColor]);

    if (!tempAisle) return null;

    const renderAisle = () => {
        switch (aisleType) {
            case 'solid-aisle':
                return <SolidAisle aisle={tempAisle} />;
            case 'dashed-aisle':
                return <DashedAisle aisle={tempAisle} />;
            case 'dotted-aisle':
                return <DottedAisle aisle={tempAisle} />;
            default:
                return null;
        }
    };

    return (
        <group>
            {renderAisle()}
        </group>
    );
}

export default ReferenceAisle;

function SolidAisle({ aisle }: { readonly aisle: Aisle }) {
    const shape = useMemo(() => {
        if (aisle.points.length < 2) return null;

        const start = new THREE.Vector3(...aisle.points[0].position);
        const end = new THREE.Vector3(...aisle.points[1].position);
        const width = aisle.type.aisleWidth || 0.1;

        const direction = new THREE.Vector3().subVectors(end, start).normalize();
        const perp = new THREE.Vector3(-direction.z, 0, direction.x).normalize();

        const leftStart = new THREE.Vector3().copy(start).addScaledVector(perp, width / 2);
        const rightStart = new THREE.Vector3().copy(start).addScaledVector(perp, -width / 2);
        const leftEnd = new THREE.Vector3().copy(end).addScaledVector(perp, width / 2);
        const rightEnd = new THREE.Vector3().copy(end).addScaledVector(perp, -width / 2);

        const shape = new THREE.Shape();
        shape.moveTo(leftStart.x, leftStart.z);
        shape.lineTo(leftEnd.x, leftEnd.z);
        shape.lineTo(rightEnd.x, rightEnd.z);
        shape.lineTo(rightStart.x, rightStart.z);
        shape.closePath();

        return shape;
    }, [aisle]);

    if (!shape) return null;

    return (
        <group
            position={[0, (aisle.points[0].layer - 1) * Constants.wallConfig.height + 0.01, 0]}
            rotation={[Math.PI / 2, 0, 0]}
        >
            <Extrude
                args={[shape, { depth: 0.01, bevelEnabled: false }]}
                receiveShadow
                castShadow
            >
                <meshStandardMaterial
                    color={aisle.type.aisleColor || '#ffffff'}
                    side={THREE.DoubleSide}
                />
            </Extrude>
        </group>
    );
}

function DashedAisle({ aisle }: { readonly aisle: Aisle }) {
    const shapes = useMemo(() => {
        if (aisle.points.length < 2) return [];

        const start = new THREE.Vector3(...aisle.points[0].position);
        const end = new THREE.Vector3(...aisle.points[1].position);
        const width = aisle.type.aisleWidth || 0.1;
        const dashLength = 0.5;
        const gapLength = 0.3;

        const direction = new THREE.Vector3().subVectors(end, start).normalize();
        const perp = new THREE.Vector3(-direction.z, 0, direction.x).normalize();

        const totalLength = new THREE.Vector3().subVectors(end, start).length();
        const segmentCount = Math.floor(totalLength / (dashLength + gapLength));

        const shapes = [];
        const directionNormalized = new THREE.Vector3().subVectors(end, start).normalize();

        for (let i = 0; i < segmentCount; i++) {
            const segmentStart = new THREE.Vector3().copy(start).addScaledVector(directionNormalized, i * (dashLength + gapLength));
            const segmentEnd = new THREE.Vector3().copy(segmentStart).addScaledVector(directionNormalized, dashLength);

            const leftStart = new THREE.Vector3().copy(segmentStart).addScaledVector(perp, width / 2);
            const rightStart = new THREE.Vector3().copy(segmentStart).addScaledVector(perp, -width / 2);
            const leftEnd = new THREE.Vector3().copy(segmentEnd).addScaledVector(perp, width / 2);
            const rightEnd = new THREE.Vector3().copy(segmentEnd).addScaledVector(perp, -width / 2);

            const shape = new THREE.Shape();
            shape.moveTo(leftStart.x, leftStart.z);
            shape.lineTo(leftEnd.x, leftEnd.z);
            shape.lineTo(rightEnd.x, rightEnd.z);
            shape.lineTo(rightStart.x, rightStart.z);
            shape.closePath();

            shapes.push(shape);
        }

        return shapes;
    }, [aisle]);

    if (shapes.length === 0) return null;

    return (
        <group
            position={[0, (aisle.points[0].layer - 1) * Constants.wallConfig.height + 0.01, 0]}
            rotation={[Math.PI / 2, 0, 0]}
        >
            {shapes.map((shape, index) => (
                <Extrude
                    key={index}
                    args={[shape, { depth: 0.01, bevelEnabled: false }]}
                    receiveShadow
                    castShadow
                >
                    <meshStandardMaterial
                        color={aisle.type.aisleColor || '#ffffff'}
                        side={THREE.DoubleSide}
                    />
                </Extrude>
            ))}
        </group>
    );
}

function DottedAisle({ aisle }: { readonly aisle: Aisle }) {
    const shapes = useMemo(() => {
        if (aisle.points.length < 2) return [];

        const start = new THREE.Vector3(...aisle.points[0].position);
        const end = new THREE.Vector3(...aisle.points[1].position);
        const width = aisle.type.aisleWidth || 0.1;
        const dotSpacing = 0.5;
        const dotRadius = width * 0.4;

        const totalLength = new THREE.Vector3().subVectors(end, start).length();
        const dotCount = Math.floor(totalLength / dotSpacing);

        const shapes = [];
        const directionNormalized = new THREE.Vector3().subVectors(end, start).normalize();

        for (let i = 0; i < dotCount; i++) {
            const dotCenter = new THREE.Vector3().copy(start).addScaledVector(directionNormalized, i * dotSpacing + dotSpacing / 2);

            const shape = new THREE.Shape();
            shape.absarc(dotCenter.x, dotCenter.z, dotRadius, 0, Math.PI * 2, false);

            shapes.push(shape);
        }

        return shapes;
    }, [aisle]);

    if (shapes.length === 0) return null;

    return (
        <group
            position={[0, (aisle.points[0].layer - 1) * Constants.wallConfig.height + 0.01, 0]}
            rotation={[Math.PI / 2, 0, 0]}
        >
            {shapes.map((shape, index) => (
                <Extrude
                    key={index}
                    args={[shape, { depth: 0.01, bevelEnabled: false }]}
                    receiveShadow
                    castShadow
                >
                    <meshStandardMaterial
                        color={aisle.type.aisleColor || '#ffffff'}
                        side={THREE.DoubleSide}
                    />
                </Extrude>
            ))}
        </group>
    );
}