import * as THREE from 'three';

import * as Types from "../../../../types/world/worldTypes";
import * as CONSTANTS from '../../../../types/world/worldConstants';

import addPointToScene from '../points/addPointToScene';
import addLineToScene from '../lines/addLineToScene';
import splitLine from '../lines/splitLine';
import removeReferenceLine from '../lines/removeReferenceLine';
import getClosestIntersection from '../lines/getClosestIntersection';
import arrayLineToObject from '../lines/lineConvertions/arrayLineToObject';
// import { setLine } from '../../../../services/factoryBuilder/lines/setLineApi';
import { Socket } from 'socket.io-client';

async function drawOnlyFloor(
    raycaster: THREE.Raycaster,
    state: Types.ThreeState,
    camera: THREE.Camera,
    plane: Types.RefMesh,
    floorPlanGroupPoint: Types.RefGroup,
    snappedPoint: Types.RefVector3,
    isSnapped: Types.RefBoolean,
    isSnappedUUID: Types.RefString,
    line: Types.RefLine,
    ispreSnapped: Types.RefBoolean,
    anglesnappedPoint: Types.RefVector3,
    isAngleSnapped: Types.RefBoolean,
    onlyFloorline: Types.RefOnlyFloorLine,
    onlyFloorlines: Types.RefOnlyFloorLines,
    lines: Types.RefLines,
    floorPlanGroupLine: Types.RefGroup,
    floorPlanGroup: Types.RefGroup,
    ReferenceLineMesh: Types.RefMesh,
    LineCreated: Types.RefBoolean,
    currentLayerPoint: Types.RefMeshArray,
    dragPointControls: Types.RefDragControl,
    setNewLines: any,
    setDeletedLines: any,
    activeLayer: Types.Number,
    socket: Socket<any>
): Promise<void> {

    //////////  Creating lines Based on the positions clicked  //////////

    if (!plane.current) return
    const intersects = raycaster.intersectObject(plane.current, true);
    const intersectsLines = raycaster.intersectObjects(floorPlanGroupLine.current.children, true);
    const intersectsPoint = raycaster.intersectObjects(floorPlanGroupPoint.current.children, true);
    const VisibleintersectsPoint = intersectsPoint.find(intersect => intersect.object.visible);
    const visibleIntersect = intersectsLines.find(intersect => intersect.object.visible && intersect.object.name !== CONSTANTS.lineConfig.referenceName);

    if ((intersectsPoint.length === 0 || VisibleintersectsPoint === undefined) && intersectsLines.length > 0 && !isSnapped.current && !ispreSnapped.current) {

        //////////  Clicked on a preexisting Line  //////////

        if (visibleIntersect && (intersectsLines[0].object.userData.linePoints[0][3] === CONSTANTS.lineConfig.floorName || intersectsLines[0].object.userData.linePoints[0][3] === CONSTANTS.lineConfig.wallName)) {
            let pointColor, lineColor;
            if (intersectsLines[0].object.userData.linePoints[0][3] === CONSTANTS.lineConfig.wallName) {
                pointColor = CONSTANTS.pointConfig.wallOuterColor;
                lineColor = CONSTANTS.lineConfig.wallColor;
            } else {
                pointColor = CONSTANTS.pointConfig.floorOuterColor;
                lineColor = CONSTANTS.lineConfig.floorColor;
            }
            let IntersectsPoint = new THREE.Vector3(intersects[0].point.x, 0.01, intersects[0].point.z);
            if (isAngleSnapped.current && line.current.length > 0 && anglesnappedPoint.current) {
                IntersectsPoint = anglesnappedPoint.current;
            }
            if (visibleIntersect.object instanceof THREE.Mesh) {
                const ThroughPoint = (visibleIntersect.object.geometry.parameters.path).getPoints(CONSTANTS.lineConfig.lineIntersectionPoints);
                let intersectionPoint = getClosestIntersection(ThroughPoint, IntersectsPoint);

                if (intersectionPoint) {

                    const newLines = splitLine(visibleIntersect, intersectionPoint, currentLayerPoint, floorPlanGroupPoint, dragPointControls, isSnappedUUID, lines, setDeletedLines, floorPlanGroupLine, socket, pointColor, lineColor, intersectsLines[0].object.userData.linePoints[0][3]);
                    setNewLines([newLines[0], newLines[1]]);

                    (line.current as Types.Line).push([new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z), isSnappedUUID.current!, activeLayer, CONSTANTS.lineConfig.floorName]);
                    
                    if (line.current.length >= 2 && line.current[0] && line.current[1]) {
                        lines.current.push(line.current as Types.Line);
                        const data = arrayLineToObject(line.current as Types.Line);

                        const email = localStorage.getItem('email')
                        const organization = (email!.split("@")[1]).split(".")[0];

                        //REST

                        // setLine(organization, data.layer!, data.line!, data.type!);

                        //SOCKET

                        const input = {
                            organization: organization,
                            layer: data.layer,
                            line: data.line,
                            type: data.type,
                            socketId: socket.id
                        }

                        socket.emit('v1:Line:create', input);

                        setNewLines([newLines[0], newLines[1], line.current]);
                        onlyFloorline.current.push(line.current as Types.Line);
                        onlyFloorlines.current.push(onlyFloorline.current);
                        onlyFloorline.current = [];

                        addLineToScene(line.current[0][0], line.current[1][0], CONSTANTS.lineConfig.floorColor, line.current, floorPlanGroupLine);

                        removeReferenceLine(floorPlanGroup, ReferenceLineMesh, LineCreated, line);
                    }
                    return;
                }
            }
        }
    }
    if (intersects.length > 0 && intersectsLines.length === 0) {

        //////////  Clicked on an empty place or a point  //////////

        let intersectionPoint = intersects[0].point;

        if (isAngleSnapped.current && line.current.length > 0 && anglesnappedPoint.current) {
            intersectionPoint = anglesnappedPoint.current;
        }
        if (isSnapped.current && line.current.length > 0 && snappedPoint.current) {
            intersectionPoint = snappedPoint.current;
        }
        if (ispreSnapped.current && snappedPoint.current) {
            intersectionPoint = snappedPoint.current;
        }

        if (!isSnapped.current && !ispreSnapped.current) {
            addPointToScene(intersectionPoint, CONSTANTS.pointConfig.floorOuterColor, currentLayerPoint, floorPlanGroupPoint, dragPointControls, isSnappedUUID, CONSTANTS.lineConfig.floorName);
        } else {
            ispreSnapped.current = false;
            isSnapped.current = false;
        }

        (line.current as Types.Line).push([new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z), isSnappedUUID.current!, activeLayer, CONSTANTS.lineConfig.floorName]);

        if (line.current.length >= 2 && line.current[0] && line.current[1]) {
            onlyFloorline.current.push(line.current as Types.Line);
            lines.current.push(line.current as Types.Line);
            const data = arrayLineToObject(line.current as Types.Line);

            const email = localStorage.getItem('email')
            const organization = (email!.split("@")[1]).split(".")[0];

            //REST

            // setLine(organization, data.layer!, data.line!, data.type!);

            //SOCKET

            const input = {
                organization: organization,
                layer: data.layer,
                line: data.line,
                type: data.type,
                socketId: socket.id
            }

            socket.emit('v1:Line:create', input);

            setNewLines([line.current]);
            addLineToScene(line.current[0][0], line.current[1][0], CONSTANTS.lineConfig.floorColor, line.current, floorPlanGroupLine);
            const lastPoint = line.current[line.current.length - 1];
            line.current = [lastPoint];
        }
        if (isSnapped.current) { //////////  Add this to stop the drawing mode after snapping  //////////
            removeReferenceLine(floorPlanGroup, ReferenceLineMesh, LineCreated, line);
            onlyFloorlines.current.push(onlyFloorline.current);
            onlyFloorline.current = [];
        }
    }
}

export default drawOnlyFloor;