import { useMemo } from "react";
import * as turf from "@turf/turf";

export function useWallClassification(walls: Walls) {
    const findRooms = () => {
        if (walls.length < 3) return [];

        const wallSet = new Map<string, Wall>();
        const positionPairSet = new Set<string>();

        const makeKey = (p1: Point, p2: Point) => {
            return [p1.pointUuid, p2.pointUuid].sort((a, b) => a.localeCompare(b)).join("-");
        };

        const makePositionPairKey = (p1: Point, p2: Point) => {
            const sortedPositions = [
                [p1.position[0].toFixed(6), p1.position[2].toFixed(6)],
                [p2.position[0].toFixed(6), p2.position[2].toFixed(6)],
            ].sort((a, b) => a[0].localeCompare(b[0]) || a[1].localeCompare(b[1]));

            return sortedPositions.map((pos) => pos.join(",")).join("|");
        };

        for (const wall of walls) {
            const [p1, p2] = wall.points;

            if (p1.pointUuid === p2.pointUuid || (p1.position[0] === p2.position[0] && p1.position[1] === p2.position[1] && p1.position[2] === p2.position[2])) {
                continue;
            }

            const positionPairKey = makePositionPairKey(p1, p2);

            if (positionPairSet.has(positionPairKey)) {
                continue;
            }

            positionPairSet.add(positionPairKey);

            const key = makeKey(p1, p2);
            if (!wallSet.has(key)) {
                wallSet.set(key, wall);
            }
        }

        const uniqueWalls = Array.from(wallSet.values());

        const lineStrings = uniqueWalls.map((wall) => {
            const coords: [number, number][] = wall.points.map((p) => [p.position[0], p.position[2]]);
            return turf.lineString(coords, { wallUuid: wall.wallUuid });
        });

        const collection = turf.featureCollection(lineStrings);

        const polygons = turf.polygonize(collection);

        const rooms: Point[][] = [];

        polygons.features.forEach((feature) => {
            if (feature.geometry.type === "Polygon") {
                const coords = feature.geometry.coordinates[0];
                const roomPoints: Point[] = [];

                for (const [x, z] of coords) {
                    const matchingPoint = uniqueWalls.flatMap((w) => w.points).find((p) => p.position[0].toFixed(6) === x.toFixed(6) && p.position[2].toFixed(6) === z.toFixed(6));
                    if (matchingPoint) {
                        roomPoints.push(matchingPoint);
                    }
                }

                if (roomPoints.length > 0 && roomPoints[0].pointUuid !== roomPoints[roomPoints.length - 1].pointUuid) {
                    roomPoints.push(roomPoints[0]);
                }

                if (roomPoints.length >= 4) {
                    rooms.push(roomPoints);
                }
            }
        });

        return rooms;
    };

    const rooms = useMemo(() => findRooms(), [walls]);

    const findWallType = (wall: Wall) => {
        const containingRooms = rooms.filter((room) => {
            for (let i = 0; i < room.length - 1; i++) {
                const p1 = room[i];
                const p2 = room[i + 1];
                if (
                    (wall.points[0].pointUuid === p1.pointUuid && wall.points[1].pointUuid === p2.pointUuid) ||
                    (wall.points[0].pointUuid === p2.pointUuid && wall.points[1].pointUuid === p1.pointUuid)
                ) {
                    return true;
                }
            }
            return false;
        });

        if (containingRooms.length === 0) {
            return {
                type: "segment",
                rooms: [],
            };
        } else if (containingRooms.length === 1) {
            return {
                type: "room",
                rooms: containingRooms,
            };
        } else {
            return {
                type: "rooms",
                rooms: containingRooms,
            };
        }
    };

    const getWallType = (wall: Wall) => {
        return findWallType(wall);
    };

    const isRoomWall = (wall: Wall): boolean => {
        const type = findWallType(wall).type;
        return type === "room" || type === "rooms";
    };

    const isSegmentWall = (wall: Wall): boolean => {
        return findWallType(wall).type === "segment";
    };

    const isWallFlipped = (wall: Wall): boolean => {
        const wallType = findWallType(wall);
        if (wallType.type === "segment") return false;

        for (const room of wallType.rooms) {
            for (let i = 0; i < room.length - 1; i++) {
                const p1 = room[i];
                const p2 = room[i + 1];
                if (wall.points[0].pointUuid === p1.pointUuid && wall.points[1].pointUuid === p2.pointUuid) {
                    return false;
                }
                if (wall.points[0].pointUuid === p2.pointUuid && wall.points[1].pointUuid === p1.pointUuid) {
                    return true;
                }
            }
        }
        return false;
    };

    return {
        rooms,
        getWallType,
        isRoomWall,
        isSegmentWall,
        findRooms,
        isWallFlipped,
    };
}
