import * as THREE from "three";
import { useEffect } from "react";
import * as turf from "@turf/turf";
import * as Types from "../../../../types/world/worldTypes";
import arrayLinesToObject from "../../../builder/geomentries/lines/lineConvertions/arrayLinesToObject";

interface PolygonGeneratorProps {
    groupRef: React.MutableRefObject<THREE.Group | null>;
    lines: Types.RefLines;
}

export default function PolygonGenerator({
    groupRef,
    lines,
}: PolygonGeneratorProps) {

    useEffect(() => {
        let allLines = arrayLinesToObject(lines.current);
        const wallLines = allLines?.filter((line) => line?.type === "WallLine");
        const aisleLines = allLines?.filter((line) => line?.type === "AisleLine")

        const wallPoints = wallLines
            .map((pair) => pair?.line.map((vals) => vals.position))
            .filter((wall): wall is THREE.Vector3[] => !!wall);

        const result = aisleLines.map((pair) =>
            pair?.line.map((point) => ({
                position: [point.position.x, point.position.z],
                uuid: point.uuid,
            }))
        );

        if (!result || result.some((line) => !line)) {
            return;
        }

        const lineFeatures = result?.map((line: any) =>
            turf.lineString(line.map((p: any) => p?.position))
        );

        const polygons = turf.polygonize(turf.featureCollection(lineFeatures));
        
        renderWallGeometry(wallPoints);

        if (polygons.features.length > 0) {
            polygons.features.forEach((feature) => {
                if (feature.geometry.type === "Polygon") {

                    const shape = new THREE.Shape();
                    const coords = feature.geometry.coordinates[0];

                    shape.moveTo(coords[0][0], coords[0][1]);

                    for (let i = 1; i < coords.length; i++) {
                        shape.lineTo(coords[i][0], coords[i][1]);
                    }
                    shape.lineTo(coords[0][0], coords[0][1]);

                    const extrudeSettings = {
                        depth: 5,
                        bevelEnabled: false,
                    };

                    const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);

                    const material = new THREE.MeshBasicMaterial({ color: "blue", transparent: true, opacity: 0.5 });
                    const mesh = new THREE.Mesh(geometry, material);
                    mesh.rotateX(Math.PI / 2);
                    mesh.name = "agv-collider";
                    mesh.position.y = 5;

                    mesh.receiveShadow = true;
                    groupRef.current?.add(mesh);
                }
            });
        }

    }, [lines.current]);

    const renderWallGeometry = (walls: THREE.Vector3[][]) => {
        walls.forEach((wall) => {
            if (wall.length < 2) return;

            for (let i = 0; i < wall.length - 1; i++) {
                const start = new THREE.Vector3(wall[i].x, wall[i].y, wall[i].z);
                const end = new THREE.Vector3(
                    wall[i + 1].x,
                    wall[i + 1].y,
                    wall[i + 1].z
                );

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

                const wallGeometry = new THREE.BoxGeometry(length, wallHeight);
                const wallMaterial = new THREE.MeshBasicMaterial({
                    color: "#aaa",
                    transparent: true,
                    opacity: 0.5,
                });

                const wallMesh = new THREE.Mesh(wallGeometry, wallMaterial);
                const midPoint = new THREE.Vector3()
                    .addVectors(start, end)
                    .multiplyScalar(0.5);
                wallMesh.position.set(midPoint.x, wallHeight / 2, midPoint.z);

                const quaternion = new THREE.Quaternion();
                quaternion.setFromUnitVectors(new THREE.Vector3(1, 0, 0), direction);
                wallMesh.quaternion.copy(quaternion);

                groupRef.current?.add(wallMesh);
            }
        });
    };

    return null;
}
