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, Html } from '@react-three/drei';
import { useBuilderStore } from '../../../../store/builder/useBuilderStore';
import { useDirectionalSnapping } from '../../point/helpers/useDirectionalSnapping';
import { usePointSnapping } from '../../point/helpers/usePointSnapping';

interface ReferenceAisleProps {
    tempPoints: Point[];
}

function ReferenceAisle({ tempPoints }: Readonly<ReferenceAisleProps>) {
    const { aisleType, aisleWidth, aisleColor, dashLength, gapLength, dotRadius, aisleLength, isFlipped, setSnappedPosition, setSnappedPoint } = useBuilderStore();
    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 finalPosition = useRef<[number, number, number] | null>(null);

    const [tempAisle, setTempAisle] = useState<Aisle | null>(null);
    const [currentPosition, setCurrentPosition] = useState<[number, number, number]>(tempPoints[0]?.position);

    const directionalSnap = useDirectionalSnapping(currentPosition, tempPoints[0]?.position || null);
    const { snapAislePoint } = usePointSnapping({ uuid: 'temp-aisle', pointType: 'Aisle', position: directionalSnap.position || [0, 0, 0] });

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

            setCurrentPosition([intersectionPoint.x, intersectionPoint.y, intersectionPoint.z]);

            if (intersectionPoint) {
                const snapped = snapAislePoint([intersectionPoint.x, intersectionPoint.y, intersectionPoint.z]);

                if (snapped.isSnapped && snapped.snappedPoint) {
                    finalPosition.current = snapped.position;
                    setSnappedPosition(snapped.position);
                    setSnappedPoint(snapped.snappedPoint);
                } else if (directionalSnap.isSnapped) {
                    finalPosition.current = directionalSnap.position;
                    setSnappedPosition(directionalSnap.position);
                    setSnappedPoint(null);
                } else {
                    finalPosition.current = [intersectionPoint.x, intersectionPoint.y, intersectionPoint.z];
                    setSnappedPosition(null);
                    setSnappedPoint(null);
                }

                if (!finalPosition.current) return;

                if (aisleType === 'solid-aisle') {
                    setTempAisle({
                        aisleUuid: 'temp-aisle',
                        points: [
                            tempPoints[0],
                            {
                                pointUuid: 'temp-point',
                                pointType: 'Aisle',
                                position: finalPosition.current,
                                layer: activeLayer
                            }
                        ],
                        type: {
                            aisleType: aisleType,
                            aisleColor: aisleColor,
                            aisleWidth: aisleWidth
                        }
                    });
                } else if (aisleType === 'dashed-aisle') {
                    setTempAisle({
                        aisleUuid: 'temp-aisle',
                        points: [
                            tempPoints[0],
                            {
                                pointUuid: 'temp-point',
                                pointType: 'Aisle',
                                position: finalPosition.current,
                                layer: activeLayer
                            }
                        ],
                        type: {
                            aisleType: aisleType,
                            aisleColor: aisleColor,
                            aisleWidth: aisleWidth,
                            dashLength: dashLength,
                            gapLength: gapLength
                        }
                    });
                } else if (aisleType === 'dotted-aisle') {
                    setTempAisle({
                        aisleUuid: 'temp-aisle',
                        points: [
                            tempPoints[0],
                            {
                                pointUuid: 'temp-point',
                                pointType: 'Aisle',
                                position: finalPosition.current,
                                layer: activeLayer
                            }
                        ],
                        type: {
                            aisleType: aisleType,
                            aisleColor: aisleColor,
                            dotRadius: dotRadius,
                            gapLength: gapLength
                        }
                    });
                } else if (aisleType === 'arrow-aisle' || aisleType === 'circle-aisle') {
                    setTempAisle({
                        aisleUuid: 'temp-aisle',
                        points: [
                            tempPoints[0],
                            {
                                pointUuid: 'temp-point',
                                pointType: 'Aisle',
                                position: finalPosition.current,
                                layer: activeLayer
                            }
                        ],
                        type: {
                            aisleType: aisleType,
                            aisleColor: aisleColor,
                            aisleWidth: aisleWidth,
                        }
                    });
                } else if (aisleType === 'arrows-aisle') {
                    setTempAisle({
                        aisleUuid: 'temp-aisle',
                        points: [
                            tempPoints[0],
                            {
                                pointUuid: 'temp-point',
                                pointType: 'Aisle',
                                position: finalPosition.current,
                                layer: activeLayer
                            }
                        ],
                        type: {
                            aisleType: aisleType,
                            aisleColor: aisleColor,
                            aisleWidth: aisleWidth,
                            aisleLength: aisleLength,
                            gapLength: gapLength
                        }
                    });
                } else if (aisleType === 'junction-aisle' || aisleType === 'arc-aisle') {
                    setTempAisle({
                        aisleUuid: 'temp-aisle',
                        points: [
                            tempPoints[0],
                            {
                                pointUuid: 'temp-point',
                                pointType: 'Aisle',
                                position: finalPosition.current,
                                layer: activeLayer
                            }
                        ],
                        type: {
                            aisleType: aisleType,
                            aisleColor: aisleColor,
                            aisleWidth: aisleWidth,
                            isFlipped: isFlipped,
                        }
                    });
                }
            }
        } else if (tempAisle !== null) {
            setTempAisle(null);
        }
    });

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

    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} />;
            case 'arrow-aisle':
                return <ArrowAisle aisle={tempAisle} />;
            case 'arrows-aisle':
                return <ArrowsAisle aisle={tempAisle} />;
            case 'circle-aisle':
                return <CircleAisle aisle={tempAisle} />;
            case 'junction-aisle':
                return <JunctionAisle aisle={tempAisle} />;
            case 'arc-aisle':
                return <ArcAisle aisle={tempAisle} />
            default:
                return null;
        }
    };

    const textPosition = new THREE.Vector3().addVectors(new THREE.Vector3(...tempAisle.points[0].position), new THREE.Vector3(...tempAisle.points[1].position)).divideScalar(2);
    const distance = new THREE.Vector3(...tempAisle.points[0].position).distanceTo(new THREE.Vector3(...tempAisle.points[1].position));

    const rendertext = () => {
        return (
            <>
                {toggleView &&
                    <Html
                        key={tempAisle.aisleUuid}
                        userData={tempAisle}
                        position={[textPosition.x, 1, textPosition.z]}
                        wrapperClass="distance-text-wrapper"
                        className="distance-text"
                        zIndexRange={[1, 0]}
                        prepend
                        sprite
                    >
                        <div
                            key={tempAisle.aisleUuid}
                            className={`distance ${tempAisle.aisleUuid}`}
                        >
                            {distance.toFixed(2)} m
                        </div>
                    </Html>
                }
            </>
        )
    }

    return (
        <group name='Aisle-Reference-Group'>
            {renderAisle()}
            {rendertext()}
        </group>
    );
}

export default ReferenceAisle;

function SolidAisle({ aisle }: { readonly aisle: Aisle }) {

    const shape = useMemo(() => {
        if (aisle.points.length < 2 || aisle.type.aisleType !== 'solid-aisle') 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 || aisle.type.aisleType !== 'dashed-aisle') 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 = aisle.type.dashLength || 0.5;
        const gapLength = aisle.type.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 + gapLength) / (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 || aisle.type.aisleType !== 'dotted-aisle') return [];

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

        const totalLength = new THREE.Vector3().subVectors(end, start).length();
        const dotCount = Math.floor((totalLength + (dotSpacing / 2)) / 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>
    );
}

function ArrowsAisle({ aisle }: { readonly aisle: Aisle }) {
    const arrows = useMemo(() => {
        if (aisle.points.length < 2 || aisle.type.aisleType !== 'arrows-aisle') 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 arrowLength = aisle.type.aisleLength || 0.6;
        const spacing = aisle.type.gapLength || 0.6;

        const direction = new THREE.Vector3().subVectors(end, start);
        const length = direction.length();
        direction.normalize();

        const count = Math.floor((length + spacing) / (arrowLength + spacing));

        const arrowShapes: { shape: THREE.Shape; position: THREE.Vector3; rotationY: number }[] = [];

        for (let i = 0; i < count; i++) {
            const initialOffset = arrowLength;
            const center = new THREE.Vector3().copy(start).addScaledVector(direction, initialOffset + i * (arrowLength + spacing));

            const shape = new THREE.Shape();
            const w = width * 0.8;
            const h = arrowLength;

            shape.moveTo(0, 0);
            shape.lineTo(w, h * 0.6);
            shape.lineTo(w * 0.4, h * 0.6);
            shape.lineTo(w * 0.4, h);
            shape.lineTo(-w * 0.4, h);
            shape.lineTo(-w * 0.4, h * 0.6);
            shape.lineTo(-w, h * 0.6);
            shape.lineTo(0, 0);

            const angle = Math.atan2(direction.x, direction.z) + Math.PI;

            arrowShapes.push({ shape, position: center, rotationY: angle });
        }

        return arrowShapes;
    }, [aisle]);

    if (arrows.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]}
        >
            {arrows.map(({ shape, position, rotationY }, index) => (
                <group key={index} position={[position.x, position.z, 0]} rotation={[0, 0, -rotationY]}>
                    <Extrude
                        args={[shape, { depth: 0.01, bevelEnabled: false }]}
                        receiveShadow
                        castShadow
                    >
                        <meshStandardMaterial
                            color={aisle.type.aisleColor || '#ffffff'}
                            side={THREE.DoubleSide}
                        />
                    </Extrude>
                </group>
            ))}
        </group>
    );
}

function ArrowAisle({ aisle }: { readonly aisle: Aisle }) {
    const arrow = useMemo(() => {
        if (aisle.points.length < 2 || aisle.type.aisleType !== 'arrow-aisle') 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);
        const length = direction.length();
        direction.normalize();

        const shape = new THREE.Shape();
        const arrowHeadLength = width * 2;
        const shaftLength = length - arrowHeadLength;

        if (shaftLength > 0) {
            shape.moveTo(0, 0);
            shape.lineTo(width, -arrowHeadLength);
            shape.lineTo(width / 2, -arrowHeadLength);
            shape.lineTo(width / 2, -length);
            shape.lineTo(-width / 2, -length);
            shape.lineTo(-width / 2, -arrowHeadLength);
            shape.lineTo(-width, -arrowHeadLength);
            shape.lineTo(0, 0);
        } else {
            shape.moveTo(0, 0);
            shape.lineTo(width, -length);
            shape.lineTo(-width, -length);
            shape.lineTo(0, 0);
        }

        shape.closePath();

        const position = end;
        const angle = Math.atan2(direction.x, direction.z);

        return { shape, position, rotationY: angle };
    }, [aisle]);

    if (!arrow) return null;

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

function CircleAisle({ aisle }: { readonly aisle: Aisle }) {
    const circle = useMemo(() => {
        if (aisle.points.length < 2 || aisle.type.aisleType !== 'circle-aisle') return null;

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

        const middleRadius = center.distanceTo(widthCenter);

        const innerRadius = Math.max(0, middleRadius - width / 2);
        const outerRadius = middleRadius + width / 2;

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

        if (innerRadius > 0) {
            const hole = new THREE.Path();
            hole.absarc(center.x, center.z, innerRadius, 0, Math.PI * 2, true);
            shape.holes.push(hole);
        }

        return {
            shape,
            rotationY: 0
        };
    }, [aisle]);

    if (!circle) 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={[circle.shape, {
                    depth: 0.01,
                    bevelEnabled: false,
                    steps: 1,
                    curveSegments: 64
                }]}
                receiveShadow
                castShadow
            >
                <meshStandardMaterial
                    color={aisle.type.aisleColor || '#ffffff'}
                    side={THREE.DoubleSide}
                />
            </Extrude>
        </group>
    );
}

function JunctionAisle({ aisle }: { readonly aisle: Aisle }) {
    const arrows = useMemo(() => {
        if (aisle.points.length < 2 || aisle.type.aisleType !== 'junction-aisle') 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 isFlipped = aisle.type.isFlipped || false;

        const direction = new THREE.Vector3().subVectors(end, start);
        const length = direction.length();
        direction.normalize();

        const mainShape = new THREE.Shape();
        const arrowHeadLength = width * 2;
        const shaftLength = length - arrowHeadLength;

        if (shaftLength > 0) {
            mainShape.moveTo(0, 0);
            mainShape.lineTo(width, -arrowHeadLength);
            mainShape.lineTo(width / 2, -arrowHeadLength);
            mainShape.lineTo(width / 2, -length);
            mainShape.lineTo(-width / 2, -length);
            mainShape.lineTo(-width / 2, -arrowHeadLength);
            mainShape.lineTo(-width, -arrowHeadLength);
            mainShape.lineTo(0, 0);
        } else {
            mainShape.moveTo(0, 0);
            mainShape.lineTo(width, -length);
            mainShape.lineTo(-width, -length);
            mainShape.lineTo(0, 0);
        }
        mainShape.closePath();

        const secondaryLength = length / 4;
        const secondaryShape = new THREE.Shape();
        const secondaryHeadLength = width * 2;
        const secondaryShaftLength = secondaryLength - secondaryHeadLength;

        if (secondaryShaftLength > 0) {
            secondaryShape.moveTo(0, 0);
            secondaryShape.lineTo(width / 2, 0);
            secondaryShape.lineTo(width / 2, secondaryShaftLength);
            secondaryShape.lineTo(width, secondaryShaftLength);
            secondaryShape.lineTo(0, secondaryLength);
            secondaryShape.lineTo(-width, secondaryShaftLength);
            secondaryShape.lineTo(-width / 2, secondaryShaftLength);
            secondaryShape.lineTo(-width / 2, 0);
            secondaryShape.lineTo(0, 0);
        } else {
            secondaryShape.moveTo(0, 0);
            secondaryShape.lineTo(width, 0);
            secondaryShape.lineTo(0, secondaryLength);
            secondaryShape.lineTo(-width, 0);
            secondaryShape.lineTo(0, 0);
        }
        secondaryShape.closePath();

        const mainPosition = end;
        const mainAngle = Math.atan2(direction.x, direction.z);

        const perpendicularDirection = isFlipped
            ? new THREE.Vector3(direction.z, 0, -direction.x).normalize()
            : new THREE.Vector3(-direction.z, 0, direction.x).normalize();

        const secondaryAngle = Math.atan2(perpendicularDirection.x, perpendicularDirection.z);

        const secondaryPosition = new THREE.Vector3().lerpVectors(start, end, 0.75);

        return [
            { shape: mainShape, position: mainPosition, rotationY: mainAngle },
            {
                shape: secondaryShape,
                position: secondaryPosition,
                rotationY: secondaryAngle + Math.PI
            }
        ];
    }, [aisle]);

    if (!arrows) return null;

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

function ArcAisle({ aisle }: { readonly aisle: Aisle }) {
    const arc = useMemo(() => {
        if (aisle.points.length < 2 || aisle.type.aisleType !== 'arc-aisle') 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.5;
        const isFlipped = aisle.type.isFlipped || false;

        const direction = new THREE.Vector3().subVectors(end, start);
        const length = direction.length();
        direction.normalize();

        const perpendicular = new THREE.Vector3(-direction.z, 0, direction.x).normalize();
        if (!isFlipped) perpendicular.negate();

        const arcHeight = length * 0.25;
        const midPoint = new THREE.Vector3().lerpVectors(start, end, 0.5);
        const controlPoint = new THREE.Vector3().copy(midPoint).addScaledVector(perpendicular, arcHeight);

        const widthOffset = perpendicular.clone().multiplyScalar(width / 2);

        const p1 = new THREE.Vector3().copy(start).add(widthOffset);
        const p2 = new THREE.Vector3().copy(end).add(widthOffset);
        const p3 = new THREE.Vector3().copy(end).sub(widthOffset);
        const p4 = new THREE.Vector3().copy(start).sub(widthOffset);

        const shape = new THREE.Shape();
        shape.moveTo(p1.x, p1.z);

        shape.quadraticCurveTo(
            controlPoint.x + widthOffset.x,
            controlPoint.z + widthOffset.z,
            p2.x, p2.z
        );

        shape.lineTo(p3.x, p3.z);

        shape.quadraticCurveTo(
            controlPoint.x - widthOffset.x,
            controlPoint.z - widthOffset.z,
            p4.x, p4.z
        );

        shape.lineTo(p1.x, p1.z);

        return {
            shape,
            position: new THREE.Vector3(0, 0, 0),
            rotationY: 0
        };
    }, [aisle]);


    if (!arc) 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={[arc.shape, {
                    depth: 0.01,
                    bevelEnabled: false,
                    curveSegments: 32
                }]}
                receiveShadow
                castShadow
            >
                <meshStandardMaterial
                    color={aisle.type.aisleColor || '#ffffff'}
                    side={THREE.DoubleSide}
                />
            </Extrude>
        </group>
    );
}