import { useEffect, useRef, useState, useMemo } from 'react';
import * as THREE from 'three';
import { useFrame, useThree } from '@react-three/fiber';
import { Extrude, Html } from '@react-three/drei';
import { useBuilderStore } from '../../../../store/builder/useBuilderStore';
import { useActiveLayer, useToolMode, useToggleView } from '../../../../store/builder/store';
import { useDirectionalSnapping } from '../../point/helpers/useDirectionalSnapping';
import { usePointSnapping } from '../../point/helpers/usePointSnapping';
import ReferenceLine from '../../line/reference/referenceLine';

interface ReferenceZoneProps {
    tempPoints: Point[];
}

function ReferenceZone({ tempPoints }: Readonly<ReferenceZoneProps>) {
    const { zoneColor, zoneHeight, 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 [tempZone, setTempZone] = useState<Zone | null>(null);
    const [currentPosition, setCurrentPosition] = useState<[number, number, number]>(tempPoints[0]?.position);

    const directionalSnap = useDirectionalSnapping(currentPosition, tempPoints[tempPoints.length - 1]?.position || null);
    const { snapZonePoint } = usePointSnapping({ uuid: 'temp-Zone', pointType: 'Zone', position: directionalSnap.position || [0, 0, 0], });

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

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

            if (!intersectionPoint) return;
            const snapped = snapZonePoint([intersectionPoint.x, intersectionPoint.y, intersectionPoint.z], tempPoints.length > 2 ? [tempPoints[0]] : []);

            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;

            const zonePoints: Point[] = [
                ...tempPoints,
                {
                    pointUuid: 'temp-point',
                    pointType: 'Zone',
                    position: finalPosition.current,
                    layer: activeLayer,
                },
            ];

            setTempZone({
                zoneUuid: 'temp-zone',
                zoneName: 'temp-zone',
                points: zonePoints,
                zoneColor,
                zoneHeight,
                viewPortPosition: [0, 0, 0],
                viewPortTarget: [0, 0, 0],
            });

        } else if (tempZone !== null) {
            setTempZone(null);
        }
    });

    useEffect(() => {
        setTempZone(null);
    }, [toolMode, toggleView, tempPoints.length, zoneColor, zoneHeight, activeLayer]);

    const allLines = useMemo(() => {
        if (!tempZone || tempZone.points.length < 2) return [];

        const lines: [Point, Point][] = [];
        const pts = tempZone.points;

        for (let i = 0; i < pts.length - 1; i++) {
            lines.push([pts[i], pts[i + 1]]);
        }

        return lines;
    }, [tempZone]);

    if (!tempZone) return null;

    return (
        <group name="Wall-Reference-Group">
            {allLines.map(([p1, p2], idx) => {
                const v1 = new THREE.Vector3(...p1.position);
                const v2 = new THREE.Vector3(...p2.position);
                const mid = new THREE.Vector3().addVectors(v1, v2).multiplyScalar(0.5);
                const dist = v1.distanceTo(v2);

                return (
                    <group key={`${p1.pointUuid}-${p2.pointUuid}`}>
                        <ReferenceLine points={[p1, p2]} />
                        {toggleView && (
                            <Html
                                position={[mid.x, 1, mid.z]}
                                wrapperClass="distance-text-wrapper"
                                className="distance-text"
                                zIndexRange={[1, 0]}
                                prepend
                                sprite
                            >
                                <div className={`distance ref-line-${idx}`}>{dist.toFixed(2)} m</div>
                            </Html>
                        )}
                    </group>
                );
            })}

            {tempPoints.length >= 3 && (
                <Zone zone={tempZone.points} />
            )}
        </group>
    );
}

export default ReferenceZone;


function Zone({ zone }: { zone: Point[] }) {
    const savedTheme: string | null = localStorage.getItem('theme');

    const shape = useMemo(() => {
        const shape = new THREE.Shape();
        const points = zone.map(p => new THREE.Vector2(p.position[0], p.position[2]));
        if (points.length < 3) return null;
        shape.moveTo(points[0].x, points[0].y);
        points.forEach((pt) => { shape.lineTo(pt.x, pt.y); });
        return shape;
    }, [zone]);

    if (!shape) return null;

    return (
        <group name="Zone-Ref" rotation={[Math.PI / 2, 0, 0]}>
            <Extrude
                args={[shape, { depth: 0.001, bevelEnabled: false }]}
                position={[0, 0, 0]}
                receiveShadow
            >
                <meshStandardMaterial color={savedTheme === "dark" ? "#007BFF" : "#007BFF"} depthWrite={false} transparent opacity={0.3} side={THREE.DoubleSide} />
            </Extrude>
        </group>
    );
}
