import * as THREE from "three";
import * as Types from "../../../types/world/worldTypes";
import * as CONSTANTS from "../../../types/world/worldConstants";
import { useThree } from "@react-three/fiber";
import {
  useToggleView,
  useActiveLayer,
  useSocketStore,
  useDeletePointOrLine,
  useUpdateScene,
  useNewLines,
  useToolMode,
} from "../../../store/builder/store";
import { useEffect } from "react";
import removeSoloPoint from "../geomentries/points/removeSoloPoint";
import removeReferenceLine from "../geomentries/lines/removeReferenceLine";
import getClosestIntersection from "../geomentries/lines/getClosestIntersection";
import addPointToScene from "../geomentries/points/addPointToScene";
import arrayLineToObject from "../geomentries/lines/lineConvertions/arrayLineToObject";
import addLineToScene from "../geomentries/lines/addLineToScene";
import loadAisles from "../geomentries/aisles/loadAisles";
import { useParams } from "react-router-dom";

const FloorGroupAilse = ({
  floorGroupAisle,
  plane,
  floorPlanGroupLine,
  floorPlanGroupPoint,
  line,
  lines,
  currentLayerPoint,
  dragPointControls,
  floorPlanGroup,
  ReferenceLineMesh,
  LineCreated,
  isSnapped,
  ispreSnapped,
  snappedPoint,
  isSnappedUUID,
  isAngleSnapped,
  anglesnappedPoint,
}: any) => {
  const { toggleView } = useToggleView();
  const { setDeletePointOrLine } = useDeletePointOrLine();
  const { toolMode } = useToolMode();
  const { socket } = useSocketStore();
  const { activeLayer } = useActiveLayer();
  const { gl, raycaster } = useThree();
  const { updateScene, setUpdateScene } = useUpdateScene();
  const { setNewLines } = useNewLines();
  const { projectId } = useParams();

  useEffect(() => {
    if (updateScene) {
      loadAisles(lines, floorGroupAisle);
      setUpdateScene(false);
    }
  }, [updateScene]);

  useEffect(() => {
    if (toolMode === "Aisle") {
      setDeletePointOrLine(false);
    } else {
      removeSoloPoint(line, floorPlanGroupLine, floorPlanGroupPoint);
      removeReferenceLine(floorPlanGroup, ReferenceLineMesh, LineCreated, line);
    }
  }, [toolMode]);

  useEffect(() => {
    const canvasElement = gl.domElement;

    let drag = false;
    let isLeftMouseDown = false;

    const onMouseDown = (evt: any) => {
      if (evt.button === 0) {
        isLeftMouseDown = true;
        drag = false;
      }
    };

    const onMouseUp = (evt: any) => {
      if (evt.button === 0) {
        isLeftMouseDown = false;
      }
    };

    const onMouseMove = () => {
      if (isLeftMouseDown) {
        drag = true;
      }
    };

    const onContextMenu = (e: any) => {
      e.preventDefault();
      if (toolMode === "Aisle") {
        removeSoloPoint(line, floorPlanGroupLine, floorPlanGroupPoint);
        removeReferenceLine(
          floorPlanGroup,
          ReferenceLineMesh,
          LineCreated,
          line
        );
      }
    };

    const onMouseClick = (evt: any) => {
      if (!plane.current || drag) return;

      const intersects = raycaster.intersectObject(plane.current, true);
      let intersectionPoint = intersects[0].point;
      const points = floorPlanGroupPoint.current?.children ?? [];
      const intersectsPoint = raycaster
        .intersectObjects(points, true)
        .find((intersect) => intersect.object.visible);
      let intersectsLines: any = raycaster.intersectObjects(
        floorPlanGroupLine.current.children,
        true
      );

      if (
        intersectsLines.length > 0 &&
        intersects &&
        intersects.length > 0 &&
        !intersectsPoint
      ) {
        const lineType = intersectsLines[0].object.userData.linePoints[0][3];
        if (lineType === CONSTANTS.lineConfig.aisleName) {
          // console.log("intersected a aisle line");
          const ThroughPoint =
            intersectsLines[0].object.geometry.parameters.path.getPoints(
              CONSTANTS.lineConfig.lineIntersectionPoints
            );
          let intersection = getClosestIntersection(
            ThroughPoint,
            intersectionPoint
          );
          if (!intersection) return;
          const point = addPointToScene(
            intersection,
            CONSTANTS.pointConfig.aisleOuterColor,
            currentLayerPoint,
            floorPlanGroupPoint,
            dragPointControls,
            undefined,
            CONSTANTS.lineConfig.aisleName
          );
          (line.current as Types.Line).push([
            new THREE.Vector3(intersection.x, 0.01, intersection.z),
            point.uuid,
            activeLayer,
            CONSTANTS.lineConfig.aisleName,
          ]);
          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];
            const userId = localStorage.getItem("userId");

            //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,
              projectId,
              userId,
            };

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

            setNewLines([line.current]);

            addLineToScene(
              line.current[0][0],
              line.current[1][0],
              CONSTANTS.pointConfig.aisleOuterColor,
              line.current,
              floorPlanGroupLine
            );
            let lastPoint = line.current[line.current.length - 1];
            line.current = [lastPoint];
          }
        }
      } else if (intersectsPoint && intersects && intersects.length > 0) {
        if (
          intersectsPoint.object.userData.type ===
          CONSTANTS.lineConfig.aisleName
        ) {
          // console.log("intersected a aisle point");
          intersectionPoint = intersectsPoint.object.position;
          (line.current as Types.Line).push([
            new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z),
            intersectsPoint.object.uuid,
            activeLayer,
            CONSTANTS.lineConfig.aisleName,
          ]);
          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];
            const userId = localStorage.getItem("userId");

            //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,
              projectId,
              userId,
            };

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

            setNewLines([line.current]);

            addLineToScene(
              line.current[0][0],
              line.current[1][0],
              CONSTANTS.pointConfig.aisleOuterColor,
              line.current,
              floorPlanGroupLine
            );
            let lastPoint = line.current[line.current.length - 1];
            line.current = [lastPoint];
            ispreSnapped.current = false;
            isSnapped.current = false;
          }
        }
      } else if (intersects && intersects.length > 0) {
        // console.log("intersected a empty area");
        let uuid: string = "";
        if (
          isAngleSnapped.current &&
          anglesnappedPoint.current &&
          line.current.length > 0
        ) {
          intersectionPoint = anglesnappedPoint.current;
          const point = addPointToScene(
            intersectionPoint,
            CONSTANTS.pointConfig.aisleOuterColor,
            currentLayerPoint,
            floorPlanGroupPoint,
            dragPointControls,
            undefined,
            CONSTANTS.lineConfig.aisleName
          );
          uuid = point.uuid;
        } else if (
          isSnapped.current &&
          snappedPoint.current &&
          line.current.length > 0
        ) {
          intersectionPoint = snappedPoint.current;
          uuid = isSnappedUUID.current!;
        } else if (ispreSnapped.current && snappedPoint.current) {
          intersectionPoint = snappedPoint.current;
          uuid = isSnappedUUID.current!;
        } else {
          const point = addPointToScene(
            intersectionPoint,
            CONSTANTS.pointConfig.aisleOuterColor,
            currentLayerPoint,
            floorPlanGroupPoint,
            dragPointControls,
            undefined,
            CONSTANTS.lineConfig.aisleName
          );
          uuid = point.uuid;
        }
        (line.current as Types.Line).push([
          new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z),
          uuid,
          activeLayer,
          CONSTANTS.lineConfig.aisleName,
        ]);

        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];
          const userId = localStorage.getItem("userId");

          //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,
            projectId,
            userId,
          };

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

          setNewLines([line.current]);

          addLineToScene(
            line.current[0][0],
            line.current[1][0],
            CONSTANTS.pointConfig.aisleOuterColor,
            line.current,
            floorPlanGroupLine
          );
          let lastPoint = line.current[line.current.length - 1];
          line.current = [lastPoint];
          ispreSnapped.current = false;
          isSnapped.current = false;
        }
      }
    };

    if (toolMode === "Aisle") {
      canvasElement.addEventListener("mousedown", onMouseDown);
      canvasElement.addEventListener("mouseup", onMouseUp);
      canvasElement.addEventListener("mousemove", onMouseMove);
      canvasElement.addEventListener("click", onMouseClick);
      canvasElement.addEventListener("contextmenu", onContextMenu);
    }

    return () => {
      canvasElement.removeEventListener("mousedown", onMouseDown);
      canvasElement.removeEventListener("mouseup", onMouseUp);
      canvasElement.removeEventListener("mousemove", onMouseMove);
      canvasElement.removeEventListener("click", onMouseClick);
      canvasElement.removeEventListener("contextmenu", onContextMenu);
    };
  }, [toolMode]);

  return (
    <group
      ref={floorGroupAisle}
      visible={!toggleView}
      name="floorGroupAisle"
    ></group>
  );
};

export default FloorGroupAilse;
