import * as THREE from 'three';
import * as turf from '@turf/turf';
import * as CONSTANTS from '../../../../types/world/worldConstants';
import * as Types from "../../../../types/world/worldTypes";

async function getRoomsFromLines(lines: Types.RefLines) {
    const rooms: Types.Rooms = [];

    if (lines.current.length > 2) {
        const linesByLayer = lines.current.reduce((acc: { [key: number]: any[] }, pair) => {
            const layer = pair[0][2];
            if (!acc[layer]) acc[layer] = [];
            acc[layer].push(pair);
            return acc;
        }, {});

        //////////  Use turf.polygonize to create polygons from the line points  //////////

        for (const layer in linesByLayer) {

            let linesInLayer = linesByLayer[layer];
            linesInLayer = linesInLayer.filter(line => line[0][3] && line[1][3] === CONSTANTS.lineConfig.wallName);
            const result = linesInLayer.map((pair: [THREE.Vector3, string, number, string][]) =>
                pair.map((point) => ({
                    position: [point[0].x, point[0].z],
                    uuid: point[1]
                }))
            );
            const lineFeatures = result.map(line => turf.lineString(line.map(p => p.position)));
            const polygons = turf.polygonize(turf.featureCollection(lineFeatures));

            let union: any[] = [];

            polygons.features.forEach((feature) => {
                union.push(feature);
            });

            if (union.length > 1) {
                const unionResult = turf.union(turf.featureCollection(union));
                if (unionResult?.geometry.type === "MultiPolygon") {
                    unionResult?.geometry.coordinates.forEach((poly) => {
                        const Coordinates = poly[0].map(([x, z]) => {
                            const matchingPoint = result.flat().find(r =>
                                r.position[0].toFixed(10) === x.toFixed(10) &&
                                r.position[1].toFixed(10) === z.toFixed(10)
                            );
                            return {
                                position: new THREE.Vector3(x, 0, z),
                                uuid: matchingPoint ? matchingPoint.uuid : ''
                            };
                        });
                        rooms.push({ coordinates: Coordinates.reverse(), layer: parseInt(layer) });
                    });
                } else if (unionResult?.geometry.type === "Polygon") {
                    const Coordinates = unionResult?.geometry.coordinates[0].map(([x, z]) => {
                        const matchingPoint = result.flat().find(r =>
                            r.position[0].toFixed(10) === x.toFixed(10) &&
                            r.position[1].toFixed(10) === z.toFixed(10)
                        );
                        return {
                            position: new THREE.Vector3(x, 0, z),
                            uuid: matchingPoint ? matchingPoint.uuid : ''
                        };
                    });
                    rooms.push({ coordinates: Coordinates.reverse(), layer: parseInt(layer) });
                }
            } else if (union.length === 1) {
                const Coordinates = union[0].geometry.coordinates[0].map(([x, z]: [number, number]) => {
                    const matchingPoint = result.flat().find(r =>
                        r.position[0].toFixed(10) === x.toFixed(10) &&
                        r.position[1].toFixed(10) === z.toFixed(10)
                    );
                    return {
                        position: new THREE.Vector3(x, 0, z),
                        uuid: matchingPoint ? matchingPoint.uuid : ''
                    };
                });
                rooms.push({ coordinates: Coordinates, layer: parseInt(layer) });
            }
        }
    }

    return rooms;
}

export default getRoomsFromLines;
