import { WalletIcon } from "../../../../components/icons/3dChartIcons";
import { useEffect, useRef, useState } from "react";
import {
  useDroppedObjectsStore,
  Zones,
} from "../../../../store/visualization/useDroppedObjectsStore";
import useModuleStore from "../../../../store/useModuleStore";
import { determinePosition } from "../../functions/determinePosition";
import { getActiveProperties } from "../../functions/getActiveProperties";
import { addingFloatingWidgets } from "../../../../services/visulization/zone/addFloatingWidgets";
import {
  DublicateIcon,
  KebabIcon,
  DeleteIcon,
} from "../../../../components/icons/ExportCommonIcons";
import DistanceLines from "./DistanceLines"; // Import the DistanceLines component
import { deleteFloatingWidgetApi } from "../../../../services/visulization/zone/deleteFloatingWidget";

import TotalCardComponent from "./cards/TotalCardComponent";
import WarehouseThroughputComponent from "./cards/WarehouseThroughputComponent";
import FleetEfficiencyComponent from "./cards/FleetEfficiencyComponent";
import { useWidgetStore } from "../../../../store/useWidgetStore";
import { useSocketStore } from "../../../../store/store";
import { useClickOutside } from "../../functions/handleWidgetsOuterClick";
import { usePlayButtonStore } from "../../../../store/usePlayButtonStore";
import { useSelectedZoneStore } from "../../../../store/visualization/useZoneStore";
interface DraggingState {
  zone: string;
  index: number;
  initialPosition: {
    top: number | "auto";
    left: number | "auto";
    right: number | "auto";
    bottom: number | "auto";
  };
}

interface DraggingState {
  zone: string;
  index: number;
  initialPosition: {
    top: number | "auto";
    left: number | "auto";
    right: number | "auto";
    bottom: number | "auto";
  };
}
const DroppedObjects: React.FC = () => {
  const { visualizationSocket } = useSocketStore();
  const { isPlaying } = usePlayButtonStore();
  const zones = useDroppedObjectsStore((state) => state.zones);

  const [openKebabId, setOpenKebabId] = useState<string | null>(null);
  const updateObjectPosition = useDroppedObjectsStore(
    (state) => state.updateObjectPosition
  );
  const { setSelectedZone, selectedZone } = useSelectedZoneStore();

  const deleteObject = useDroppedObjectsStore((state) => state.deleteObject);

  const duplicateObject = useDroppedObjectsStore(
    (state) => state.duplicateObject
  );
  const [draggingIndex, setDraggingIndex] = useState<DraggingState | null>(
    null
  );
  const [offset, setOffset] = useState<[number, number] | null>(null);
  const { selectedChartId, setSelectedChartId } = useWidgetStore();

  const [activeEdges, setActiveEdges] = useState<{
    vertical: "top" | "bottom";
    horizontal: "left" | "right";
  } | null>(null); // State to track active edges for distance lines

  const [currentPosition, setCurrentPosition] = useState<{
    top: number | "auto";
    left: number | "auto";
    right: number | "auto";
    bottom: number | "auto";
  } | null>(null); // State to track the current position during drag
  const animationRef = useRef<number | null>(null);
  const { activeModule } = useModuleStore();
  const chartWidget = useRef<HTMLDivElement>(null);

  // useClickOutside(chartWidget, () => {
  //   setSelectedChartId(null);
  // });
  const kebabRef = useRef<HTMLDivElement>(null);

  // Clean up animation frame on unmount
  useEffect(() => {
    return () => {
      if (animationRef.current) {
        cancelAnimationFrame(animationRef.current);
      }
    };
  }, []);
  useEffect(() => {
    const handleClickOutside = (event: MouseEvent) => {
      if (
        kebabRef.current &&
        !kebabRef.current.contains(event.target as Node)
      ) {
        setOpenKebabId(null);
      }
    };

    // Add event listener when component mounts
    document.addEventListener("mousedown", handleClickOutside);

    // Clean up event listener when component unmounts
    return () => {
      document.removeEventListener("mousedown", handleClickOutside);
    };
  }, []);

  const zoneEntries = Object.entries(zones);
  if (zoneEntries.length === 0) return null;
  const [zoneName, zone] = zoneEntries[0];

  function handleDuplicate(zoneName: string, index: number) {
    setOpenKebabId(null);
    duplicateObject(zoneName, index); // Call the duplicateObject method from the store
    setSelectedChartId(null);
  }

  async function handleDelete(zoneName: string, id: string) {
    try {
      setSelectedChartId(null);
      const email = localStorage.getItem("email") || "";
      const organization = email?.split("@")[1]?.split(".")[0];

      let deleteFloatingWidget = {
        floatWidgetID: id,
        organization: organization,
        zoneId: zone.zoneId,
      };

      if (visualizationSocket) {
        visualizationSocket.emit("v2:viz-float:delete", deleteFloatingWidget);
      }
      deleteObject(zoneName, id);

      // let res = await deleteFloatingWidgetApi(id, organization);
      // s

      // if (res.message === "FloatingWidget deleted successfully") {
      //   deleteObject(zoneName, id, index); // Call the deleteObject method from the store
      // }
    } catch (error) {}
  }

  const handlePointerDown = (event: React.PointerEvent, index: number) => {
    if (
      (event.target as HTMLElement).closest(".kebab-options") ||
      (event.target as HTMLElement).closest(".kebab")
    ) {
      return; // Prevent dragging when clicking on the kebab menu or its options
    }
    const obj = zone.objects[index];
    const element = event.currentTarget as HTMLElement;
    element.setPointerCapture(event.pointerId);
    const container = document.getElementById("real-time-vis-canvas");
    if (!container) return;

    const rect = container.getBoundingClientRect();
    const relativeX = event.clientX - rect.left;
    const relativeY = event.clientY - rect.top;

    // Determine active properties for the initial position
    const [activeProp1, activeProp2] = getActiveProperties(obj.position);

    // Set active edges for distance lines
    const vertical = activeProp1 === "top" ? "top" : "bottom";
    const horizontal = activeProp2 === "left" ? "left" : "right";
    setActiveEdges({ vertical, horizontal });

    // Store the initial position strategy and active edges
    setDraggingIndex({
      zone: zoneName,
      index,
      initialPosition: { ...obj.position },
    });

    // Calculate offset from mouse to object edges
    let offsetX = 0;
    let offsetY = 0;

    if (activeProp1 === "top") {
      offsetY = relativeY - (obj.position.top as number);
    } else {
      offsetY = rect.height - relativeY - (obj.position.bottom as number);
    }

    if (activeProp2 === "left") {
      offsetX = relativeX - (obj.position.left as number);
    } else {
      offsetX = rect.width - relativeX - (obj.position.right as number);
    }

    setOffset([offsetY, offsetX]);

    // Add native event listeners for smoother tracking
    const handlePointerMoveNative = (e: PointerEvent) => {
      if (!draggingIndex || !offset) return;
      if (isPlaying === true) return;

      const rect = container.getBoundingClientRect();
      const relativeX = e.clientX - rect.left;
      const relativeY = e.clientY - rect.top;

      // Use requestAnimationFrame for smooth updates
      animationRef.current = requestAnimationFrame(() => {
        // Dynamically determine the current position strategy
        const newPositionStrategy = determinePosition(
          rect,
          relativeX,
          relativeY
        );
        const [activeProp1, activeProp2] =
          getActiveProperties(newPositionStrategy);

        // Update active edges for distance lines
        const vertical = activeProp1 === "top" ? "top" : "bottom";
        const horizontal = activeProp2 === "left" ? "left" : "right";
        setActiveEdges({ vertical, horizontal });

        // Calculate new position based on the active properties
        let newY = 0;
        let newX = 0;

        if (activeProp1 === "top") {
          newY = relativeY - offset[0];
        } else {
          newY = rect.height - (relativeY + offset[0]);
        }

        if (activeProp2 === "left") {
          newX = relativeX - offset[1];
        } else {
          newX = rect.width - (relativeX + offset[1]);
        }

        // Apply boundaries
        newX = Math.max(0, Math.min(rect.width - 50, newX));
        newY = Math.max(0, Math.min(rect.height - 50, newY));

        // Create new position object
        const newPosition = {
          ...newPositionStrategy,
          [activeProp1]: newY,
          [activeProp2]: newX,
          // Clear opposite properties
          [activeProp1 === "top" ? "bottom" : "top"]: "auto",
          [activeProp2 === "left" ? "right" : "left"]: "auto",
        };

        // Update the current position state for DistanceLines
        setCurrentPosition(newPosition);
        updateObjectPosition(zoneName, draggingIndex.index, newPosition);
      });
    };

    const handlePointerUpNative = async (e: PointerEvent) => {
      // Clean up native event listeners
      element.removeEventListener("pointermove", handlePointerMoveNative);
      element.removeEventListener("pointerup", handlePointerUpNative);
      element.releasePointerCapture(e.pointerId);

      if (!draggingIndex || !offset) return;

      const rect = container.getBoundingClientRect();
      const relativeX = e.clientX - rect.left;
      const relativeY = e.clientY - rect.top;

      // Determine final position strategy
      const finalPosition = determinePosition(rect, relativeX, relativeY);
      const [activeProp1, activeProp2] = getActiveProperties(finalPosition);

      // Calculate final position
      let finalY = 0;
      let finalX = 0;

      if (activeProp1 === "top") {
        finalY = relativeY - offset[0];
      } else {
        finalY = rect.height - (relativeY + offset[0]);
      }

      if (activeProp2 === "left") {
        finalX = relativeX - offset[1];
      } else {
        finalX = rect.width - (relativeX + offset[1]);
      }

      // Apply boundaries
      finalX = Math.max(0, Math.min(rect.width - 50, finalX));
      finalY = Math.max(0, Math.min(rect.height - 50, finalY));

      const boundedPosition = {
        ...finalPosition,
        [activeProp1]: finalY,
        [activeProp2]: finalX,
        [activeProp1 === "top" ? "bottom" : "top"]: "auto",
        [activeProp2 === "left" ? "right" : "left"]: "auto",
      };

      try {
        // Save to backend
        const email = localStorage.getItem("email") || "";
        const organization = email?.split("@")[1]?.split(".")[0];
        const response = await addingFloatingWidgets(
          zone.zoneId,
          organization,
          {
            ...zone.objects[draggingIndex.index],
            position: boundedPosition,
          }
        );

        if (response.message === "Widget updated successfully") {
          updateObjectPosition(zoneName, draggingIndex.index, boundedPosition);
        }
      } catch (error) {
      } finally {
        setDraggingIndex(null);
        setOffset(null);
        setActiveEdges(null);
        setCurrentPosition(null);

        if (animationRef.current) {
          cancelAnimationFrame(animationRef.current);
          animationRef.current = null;
        }
      }
    };

    // Add native event listeners
    element.addEventListener("pointermove", handlePointerMoveNative);
    element.addEventListener("pointerup", handlePointerUpNative);
  };

  const handlePointerMove = (event: React.PointerEvent) => {
    if (!draggingIndex || !offset) return;
    if (isPlaying === true) return;
    const container = document.getElementById("real-time-vis-canvas");
    if (!container) return;

    const rect = container.getBoundingClientRect();
    const relativeX = event.clientX - rect.left;
    const relativeY = event.clientY - rect.top;

    // Dynamically determine the current position strategy
    const newPositionStrategy = determinePosition(rect, relativeX, relativeY);
    const [activeProp1, activeProp2] = getActiveProperties(newPositionStrategy);

    // Update active edges for distance lines
    const vertical = activeProp1 === "top" ? "top" : "bottom";
    const horizontal = activeProp2 === "left" ? "left" : "right";
    setActiveEdges({ vertical, horizontal });

    // Calculate new position based on the active properties
    let newY = 0;
    let newX = 0;

    if (activeProp1 === "top") {
      newY = relativeY - offset[0];
    } else {
      newY = rect.height - (relativeY + offset[0]);
    }

    if (activeProp2 === "left") {
      newX = relativeX - offset[1];
    } else {
      newX = rect.width - (relativeX + offset[1]);
    }

    // Apply boundaries
    newX = Math.max(0, Math.min(rect.width - 50, newX));
    newY = Math.max(0, Math.min(rect.height - 50, newY));

    // Create new position object
    const newPosition = {
      ...newPositionStrategy,
      [activeProp1]: newY,
      [activeProp2]: newX,
      // Clear opposite properties
      [activeProp1 === "top" ? "bottom" : "top"]: "auto",
      [activeProp2 === "left" ? "right" : "left"]: "auto",
    };

    // Update the current position state for DistanceLines
    setCurrentPosition(newPosition);
    // Update position immediately without animation frame
    updateObjectPosition(zoneName, draggingIndex.index, newPosition);

    // if (!animationRef.current) {
    //   animationRef.current = requestAnimationFrame(() => {
    //     updateObjectPosition(zoneName, draggingIndex.index, newPosition);
    //     animationRef.current = null;
    //   });
    // }
  };

  const handlePointerUp = async (event: React.PointerEvent<HTMLDivElement>) => {
    try {
      if (!draggingIndex || !offset) return;
      if (isPlaying === true) return;

      const container = document.getElementById("real-time-vis-canvas");
      if (!container) return;

      const rect = container.getBoundingClientRect();
      const relativeX = event.clientX - rect.left;
      const relativeY = event.clientY - rect.top;

      // Determine final position strategy
      const finalPosition = determinePosition(rect, relativeX, relativeY);
      const [activeProp1, activeProp2] = getActiveProperties(finalPosition);

      // Calculate final position
      let finalY = 0;
      let finalX = 0;

      if (activeProp1 === "top") {
        finalY = relativeY - offset[0];
      } else {
        finalY = rect.height - (relativeY + offset[0]);
      }

      if (activeProp2 === "left") {
        finalX = relativeX - offset[1];
      } else {
        finalX = rect.width - (relativeX + offset[1]);
      }

      // Apply boundaries
      finalX = Math.max(0, Math.min(rect.width - 50, finalX));
      finalY = Math.max(0, Math.min(rect.height - 50, finalY));

      const boundedPosition = {
        ...finalPosition,
        [activeProp1]: finalY,
        [activeProp2]: finalX,
        // Clear opposite properties
        [activeProp1 === "top" ? "bottom" : "top"]: "auto",
        [activeProp2 === "left" ? "right" : "left"]: "auto",
      };

      // Save to backend
      const email = localStorage.getItem("email") || "";
      const organization = email?.split("@")[1]?.split(".")[0];
      // const response = await addingFloatingWidgets(zone.zoneId, organization, {
      //   ...zone.objects[draggingIndex.index],
      //   position: boundedPosition,
      // });

      let updateFloatingWidget = {
        organization: organization,
        widget: {
          ...zone.objects[draggingIndex.index],
          position: boundedPosition,
        },
        index: draggingIndex.index,
        zoneId: zone.zoneId,
      };
      if (visualizationSocket) {
        visualizationSocket.emit("v2:viz-float:add", updateFloatingWidget);
      }

      // if (response.message === "Widget updated successfully") {

      updateObjectPosition(zoneName, draggingIndex.index, boundedPosition);
      // }

      // // Clean up
      // setDraggingIndex(null);
      // setOffset(null);
      // setActiveEdges(null); // Clear active edges
      // setCurrentPosition(null); // Reset current position
      // if (animationRef.current) {
      //   cancelAnimationFrame(animationRef.current);
      //   animationRef.current = null;
      // }
    } catch (error) {
    } finally {
      // Clean up regardless of success or failure
      setDraggingIndex(null);
      setOffset(null);
      setActiveEdges(null);
      setCurrentPosition(null);

      // Cancel any pending animation frame
      if (animationRef.current) {
        cancelAnimationFrame(animationRef.current);
        animationRef.current = null;
      }
    }
  };

  const handleKebabClick = (id: string, event: React.MouseEvent) => {
    event.stopPropagation();
    setOpenKebabId((prevId) => (prevId === id ? null : id));
  };

  const containerHeight = getComputedStyle(
    document.documentElement
  ).getPropertyValue("--realTimeViz-container-height");
  const containerWidth = getComputedStyle(
    document.documentElement
  ).getPropertyValue("--realTimeViz-container-width");

  const heightMultiplier = parseFloat(containerHeight) * 0.14;

  const widthMultiplier = parseFloat(containerWidth) * 0.13;

  return (
    <div
      onPointerMove={handlePointerMove}
      onPointerUp={handlePointerUp}
      className="floating-wrapper"
    >
      {zone?.objects?.map((obj, index) => {
        const topPosition =
          typeof obj?.position?.top === "number"
            ? `calc(${obj?.position?.top}px + ${
                isPlaying && selectedZone?.activeSides?.includes("top")
                  ? `${heightMultiplier - 55}px`
                  : "0px"
              })`
            : "auto";

        const leftPosition =
          typeof obj?.position?.left === "number"
            ? `calc(${obj?.position?.left}px + ${
                isPlaying && selectedZone?.activeSides?.includes("left")
                  ? `${widthMultiplier - 150}px`
                  : "0px"
              })`
            : "auto";

        const rightPosition =
          typeof obj?.position?.right === "number"
            ? `calc(${obj?.position?.right}px + ${
                isPlaying && selectedZone?.activeSides?.includes("right")
                  ? `${widthMultiplier - 150}px`
                  : "0px"
              })`
            : "auto";
        const bottomPosition =
          typeof obj?.position?.bottom === "number"
            ? `calc(${obj?.position?.bottom}px + ${
                isPlaying && selectedZone?.activeSides?.includes("bottom")
                  ? `${heightMultiplier - 55}px`
                  : "0px"
              })`
            : "auto";

        return (
          <div
            key={obj.id}
            className={`${obj.className} ${
              selectedChartId?.id === obj.id && "activeChart"
            } `}
            ref={chartWidget}
            style={{
              position: "absolute",
              top: topPosition,
              left: leftPosition,
              right: rightPosition,
              bottom: bottomPosition,
              pointerEvents: isPlaying ? "none" : "auto",
              minHeight: `${
                obj.className === "warehouseThroughput" && "150px !important"
              } `,
            }}
            onPointerDown={(event) => {
              setSelectedChartId(obj);
              handlePointerDown(event, index);
            }}
          >
            {obj.className === "floating total-card" ? (
              <TotalCardComponent object={obj} />
            ) : obj.className === "warehouseThroughput floating" ? (
              <WarehouseThroughputComponent object={obj} />
            ) : obj.className === "fleetEfficiency floating" ? (
              <FleetEfficiencyComponent object={obj} />
            ) : null}

            <div
              className="icon kebab"
              ref={kebabRef}
              onClick={(event) => {
                event.stopPropagation();
                handleKebabClick(obj.id, event);
              }}
            >
              <KebabIcon />
            </div>

            {openKebabId === obj.id && (
              <div className="kebab-options" ref={kebabRef}>
                <div
                  className="dublicate btn"
                  onClick={(event) => {
                    event.stopPropagation();
                    handleDuplicate(zoneName, index); // Call the duplicate handler
                  }}
                >
                  <div className="icon">
                    <DublicateIcon />
                  </div>
                  <div className="label">Duplicate</div>
                </div>
                <div
                  className="edit btn"
                  onClick={(event) => {
                    event.stopPropagation();
                    handleDelete(zoneName, obj.id); // Call the delete handler
                  }}
                >
                  <div className="icon">
                    <DeleteIcon />
                  </div>
                  <div className="label">Delete</div>
                </div>
              </div>
            )}
          </div>
        );
      })}

      {/* Render DistanceLines component during drag */}
      {isPlaying === false &&
        draggingIndex !== null &&
        activeEdges !== null &&
        currentPosition !== null && (
          <DistanceLines
            obj={{
              position: {
                top:
                  currentPosition.top !== "auto"
                    ? currentPosition.top
                    : undefined,
                bottom:
                  currentPosition.bottom !== "auto"
                    ? currentPosition.bottom
                    : undefined,
                left:
                  currentPosition.left !== "auto"
                    ? currentPosition.left
                    : undefined,
                right:
                  currentPosition.right !== "auto"
                    ? currentPosition.right
                    : undefined,
              },
            }}
            activeEdges={activeEdges}
          />
        )}
    </div>
  );
};

export default DroppedObjects;
