import { useEffect, useState } from "react";
import { getLines } from "../../../../../services/factoryBuilder/lines/getLinesApi";
import * as THREE from "three";
import {
  useActiveLayer,
  useDeletedLines,
  useNewLines,
  useRoomsState,
  useToggleView,
} from "../../../../../store/builder/store";
import objectLinesToArray from "../lineConvertions/objectLinesToArray";
import { Html } from "@react-three/drei";
import { Vector2 } from "three";
import * as Types from "../../../../../types/world/worldTypes";
import getRoomsFromLines from "../getRoomsFromLines";
import * as turf from '@turf/turf';
import { useParams } from "react-router-dom";
import { getUserData } from "../../../../../functions/getUserData";
import { useVersionContext } from "../../../version/versionContext";

const DistanceText = () => {
  const [lines, setLines] = useState<
    {
      distance: string;
      position: THREE.Vector3;
      userData: Types.Line;
      layer: string;
    }[]
  >([]);
  const { activeLayer } = useActiveLayer();
  const { toggleView } = useToggleView();
  const { newLines, setNewLines } = useNewLines();
  const { deletedLines, setDeletedLines } = useDeletedLines();
  const [linesState, setLinesState] = useState<Types.Lines>([]);
  const { roomsState, setRoomsState } = useRoomsState();
  const { selectedVersionStore } = useVersionContext();
  const { selectedVersion } = selectedVersionStore();
  const { projectId } = useParams();
  const { organization, email } = getUserData();

  useEffect(() => {

    if (linesState.length === 0) return;
    const getLines = async () => {
      const points3D = linesState.map(line => {
        const startPoint = line[0][0]; // First point of each wall line
        return [startPoint.x, 0, startPoint.z];
      });

      // Ensure the polygon is closed
      if (
        points3D[0][0] !== points3D[points3D.length - 1][0] ||
        points3D[0][1] !== points3D[points3D.length - 1][1]
      ) {
        points3D.push(points3D[0]);
      }

      // Convert to 2D for turf (x, z)
      const coords2D = points3D.map(p => [p[0], p[1]]);

      const projected = points3D.map((p: any) => new Vector2(p[0], p[1]));

      // Shoelace formula for 2D polygon
      let area = 0;
      const n = projected.length;
      for (let i = 0; i < n - 1; i++) {
        const curr = projected[i];
        const next = projected[i + 1];
        area += curr.x * next.y - next.x * curr.y;

      }

      // return Math.abs(area) / 2;

      // Build polygon and compute area
      // const polygon = turf.polygon([coords2D]);
      // const area = turf.area(polygon);
      // const area = computeAreaFrom3DPoints(coords2D)

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


        for (const layer in linesByLayer) {
          const rooms: Types.Rooms = await getRoomsFromLines({ current: linesByLayer[layer] });
          setRoomsState(rooms)
        }
      }
    }
    getLines();
  }, [linesState, roomsState])


  useEffect(() => {
    if (!email || !selectedVersion) return;

    getLines(organization, projectId, selectedVersion?.versionId || '').then((data) => {
      data = objectLinesToArray(data);
      setLinesState(data);

      const lines = data
        .filter((line: Types.Line) => line[0][2] === activeLayer)
        .map((line: Types.Line) => {
          const point1 = new THREE.Vector3(
            line[0][0].x,
            line[0][0].y,
            line[0][0].z
          );
          const point2 = new THREE.Vector3(
            line[1][0].x,
            line[1][0].y,
            line[1][0].z
          );
          const distance = point1.distanceTo(point2);
          const midpoint = new THREE.Vector3()
            .addVectors(point1, point2)
            .divideScalar(2);
          return {
            distance: distance.toFixed(1),
            position: midpoint,
            userData: line,
            layer: activeLayer,
          };
        });
      setLines(lines);
    });
  }, [activeLayer, selectedVersion?.versionId]);

  useEffect(() => {
    if (newLines.length > 0) {
      if (newLines[0][0][2] !== activeLayer) return;
      const newLinesData = newLines.map((line: Types.Line) => {
        const point1 = new THREE.Vector3(
          line[0][0].x,
          line[0][0].y,
          line[0][0].z
        );
        const point2 = new THREE.Vector3(
          line[1][0].x,
          line[1][0].y,
          line[1][0].z
        );
        const distance = point1.distanceTo(point2);
        const midpoint = new THREE.Vector3()
          .addVectors(point1, point2)
          .divideScalar(2);

        return {
          distance: distance.toFixed(1),
          position: midpoint,
          userData: line,
          layer: activeLayer,
        };
      });
      setLines((prevLines) => [...prevLines, ...newLinesData]);
      setLinesState((prevLines) => [...prevLines, ...newLines]);
      setNewLines([]);
    }
  }, [newLines, activeLayer]);

  useEffect(() => {
    if ((deletedLines as Types.Lines).length > 0) {
      setLines((prevLines) =>
        prevLines.filter(
          (line) =>
            !deletedLines.some(
              (deletedLine: any) =>
                deletedLine[0][1] === line.userData[0][1] &&
                deletedLine[1][1] === line.userData[1][1]
            )
        )
      );

      setLinesState(prev =>
        prev.filter(line =>
          !(deletedLines as Types.Lines).some(
            deleted =>
              line[0][1] === deleted[0][1] && line[1][1] === deleted[1][1]
          )
        )
      );

      setDeletedLines([]);
      setRoomsState([])
    }
  }, [deletedLines]);

  return (
    <>
      {toggleView && (
        <group name="Distance_Text">
          {lines.map((text) => (
            <Html
              // data
              key={`${text.userData[0][1]}_${text.userData[1][1]}`}
              userData={text.userData}
              position={[text.position.x, 1, text.position.z]}
              // class
              wrapperClass="distance-text-wrapper"
              className="distance-text"
              // other
              zIndexRange={[1, 0]}
              prepend
              sprite
            >
              <div
                key={`${text.userData[0][1]}_${text.userData[1][1]}`}
                className={`distance line-${text.userData[0][1]}_${text.userData[1][1]}_${text.layer}`}
              >
                {text.distance} m
              </div>
            </Html>
          ))}
        </group>
      )}
    </>
  );
};

export default DistanceText;
