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";
import getRoomsFromLines from '../lines/getRoomsFromLines';

async function loadWalls(
    lines: Types.RefLines,
    setWalls: any,
): Promise<void> {
    //////////  Removes the old walls if any, Checks if there is any overlapping in lines if any updates it , starts function that creates floor and roof  //////////

    const Walls: Types.Walls = [];
    const Rooms: Types.Rooms = [];

    localStorage.setItem("Lines", JSON.stringify(lines.current));

    if (lines.current.length > 1) {

        //////////  Add Walls that are forming a room  ////////// 

        const wallSet = new Set<string>();

        const rooms: Types.Rooms = await getRoomsFromLines(lines);
        Rooms.push(...rooms);

        Rooms.forEach(({ coordinates: room, layer }) => {
            for (let i = 0; i < room.length - 1; i++) {
                const uuid1 = room[i].uuid;
                const uuid2 = room[(i + 1) % room.length].uuid;
                const wallId = `${uuid1}_${uuid2}`;

                if (!wallSet.has(wallId)) {
                    const p1 = room[i].position;
                    const p2 = room[(i + 1) % room.length].position;

                    const shape = new THREE.Shape();
                    shape.moveTo(0, 0);
                    shape.lineTo(0, CONSTANTS.wallConfig.height);
                    shape.lineTo(p2.distanceTo(p1), CONSTANTS.wallConfig.height);
                    shape.lineTo(p2.distanceTo(p1), 0);
                    shape.lineTo(0, 0);

                    const extrudeSettings = {
                        depth: CONSTANTS.wallConfig.width,
                        bevelEnabled: false
                    };
                    const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);
                    const angle = Math.atan2(p2.z - p1.z, p2.x - p1.x);
                    Walls.push([geometry, [0, -angle, 0], [p1.x, (layer - 1) * CONSTANTS.wallConfig.height, p1.z], "RoomWall", layer]);

                    wallSet.add(wallId);
                }
            }
        });

        //////////  Add Walls that are not forming any room  ////////// 

        lines.current.forEach(line => {
            if (line[0][3] && line[1][3] !== CONSTANTS.lineConfig.wallName) {
                return;
            }
            const [uuid1, uuid2] = line.map(point => point[1]);
            let isInRoom = false;
            const lineLayer = line[0][2];

            for (let room of Rooms) {
                const roomLayer = room.layer;
                if (roomLayer !== lineLayer) continue;
                for (let i = 0; i < room.coordinates.length - 1; i++) {
                    const roomUuid1 = room.coordinates[i].uuid;
                    const roomUuid2 = room.coordinates[(i + 1) % room.coordinates.length].uuid;
                    if (
                        (uuid1 === roomUuid1 && uuid2 === roomUuid2) ||
                        (uuid1 === roomUuid2 && uuid2 === roomUuid1)
                    ) {
                        isInRoom = true;
                        break;
                    }
                }
                if (isInRoom) break;
            }

            if (!isInRoom) {
                const p1 = new THREE.Vector3(line[0][0].x, 0, line[0][0].z);
                const p2 = new THREE.Vector3(line[1][0].x, 0, line[1][0].z);

                let isCollinear = false;
                for (let room of Rooms) {
                    if (room.layer !== lineLayer) continue;
                    for (let i = 0; i < room.coordinates.length - 1; i++) {
                        const roomP1 = room.coordinates[i].position;
                        const roomP2 = room.coordinates[(i + 1) % room.coordinates.length].position;
                        const lineFeature = turf.lineString([[p1.x, p1.z], [p2.x, p2.z]]);
                        const roomFeature = turf.lineString([[roomP1.x, roomP1.z], [roomP2.x, roomP2.z]]);
                        if (turf.booleanOverlap(lineFeature, roomFeature)) {
                            isCollinear = true;
                            break;
                        }
                    }
                    if (isCollinear) break;
                }

                if (!isCollinear) {
                    const shape = new THREE.Shape();
                    shape.moveTo(0, 0);
                    shape.lineTo(0, CONSTANTS.wallConfig.height);
                    shape.lineTo(p2.distanceTo(p1), CONSTANTS.wallConfig.height);
                    shape.lineTo(p2.distanceTo(p1), 0);
                    shape.lineTo(0, 0);

                    const extrudeSettings = {
                        depth: CONSTANTS.wallConfig.width,
                        bevelEnabled: false
                    };
                    const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);
                    const angle = Math.atan2(p2.z - p1.z, p2.x - p1.x);
                    Walls.push([geometry, [0, -angle, 0], [p1.x, (lineLayer - 1) * CONSTANTS.wallConfig.height, p1.z], "SegmentWall", lineLayer]);
                }
            }
        });
        setWalls(Walls);
    }else{
        setWalls([]);
    }
}

export default loadWalls;
