import { useCallback, useContext, useMemo, useState } from "react";
import CanvasContext from "./Context/canvasContext/CanvasContext";
import ActiveObjectContext from "./Context/activeObject/ObjectContext";
import { fabric } from "fabric";
import {
  Tooltip,
  TooltipContent,
  TooltipProvider,
  TooltipTrigger,
} from "./ui/tooltip";
import { Button } from "./ui/button";
import {
  BringToFront,
  SendToBack,
  CopyPlus,
  GroupIcon,
  SquareX,
  Trash2,
  UngroupIcon,
  Layers,
} from "lucide-react";
import { Popover, PopoverContent, PopoverTrigger } from "./ui/popover";
import { useMutation } from "@tanstack/react-query";
import { deleteImage } from "../api/uploadApi";
import { toast } from "../hooks/use-toast";
import useProject from "@/hooks/useProject";

export const ObjectShortcut = ({ value }) => {
  const { canvas } = useContext(CanvasContext);
  const { setActiveObject, activeObject } = useContext(ActiveObjectContext);
  const [isPopoverOpen, setIsPopoverOpen] = useState(false);

  const activeObjects = canvas.getActiveObjects();
  const multipleObjects = activeObjects.length > 1;
  const objectActive = canvas.getActiveObject();
  const isGroupObject = objectActive && objectActive.type === "group";

  const { projectData, projectUpdate, id } = useProject();

  const groupSelectedObjects = () => {
    const activeObjects = canvas.getActiveObjects(); // Get selected objects
    if (activeObjects.length > 1) {
      canvas.discardActiveObject();

      const group = new fabric.Group(activeObjects, {
        left: canvas?.width / 2,
        top: canvas?.height / 2,
        originX: "center",
        originY: "center",
        selectable: true, // Allow group selection
        subTargetCheck: true, // Allow individual object selection
        hasControls: true, // Enable resizing/movement of the group
      });
      canvas.remove(...activeObjects);
      canvas.add(group);
      canvas.setActiveObject(group);
      setActiveObject(group);
      canvas.renderAll();
      const object = canvas.toJSON(['id', 'selectable']); // Include any custom properties you need
      const updateData = { ...projectData?.data, object };
      // Wait for the project update before continuing
      projectUpdate({ id, updateData });
    } else {
      toast({
        title: "Select at least two objects",
        description: "Please select at least two objects to group.",
        variant: "destructive",
      })
    }
  };

  const ungroupSelectedObjects = () => {
    const activeObject = canvas.getActiveObject();
    if (activeObject && activeObject.type === "group") {
      const groupObjects = activeObject._objects;

      canvas.discardActiveObject();
      canvas.remove(activeObject);
      setActiveObject(null);

      const ungroupedObjects = [];

      groupObjects.forEach((object) => {
        // Calculate absolute position
        const objLeft = object.left * activeObject.scaleX + activeObject.left;
        const objTop = object.top * activeObject.scaleY + activeObject.top;

        object.set({
          left: objLeft,
          top: objTop,
          scaleX: object.scaleX * activeObject.scaleX,
          scaleY: object.scaleY * activeObject.scaleY,
          angle: object.angle + activeObject.angle,
          hasControls: true,
          selectable: true,
          group: null,
          originX: "center",
          originY: "center",
        });

        object.setCoords();

        canvas.add(object);

        ungroupedObjects.push(object);
      });

      const selection = new fabric.ActiveSelection(ungroupedObjects, {
        canvas: canvas,
        originX: "center",
        originY: "center",
      });

      canvas.setActiveObject(selection);
      setActiveObject(selection);

      canvas.renderAll();

      const object = canvas.toJSON(['id', 'selectable']); // Include any custom properties you need
      const updateData = { ...projectData?.data, object };
      // Wait for the project update before continuing
      projectUpdate({ id, updateData });
    }
  };

  // Check if object is at front or back
  const objectPosition = useMemo(() => {
    if (!activeObject || !canvas) {
      return { isAtFront: false, isAtBack: false };
    }

    const allObjects = canvas.getObjects();
    const index = allObjects.indexOf(activeObject);

    return {
      isAtFront: index === allObjects.length - 1,
      isAtBack: index === 0,
    };
  }, [activeObject, canvas]);

  // Layer ordering functions with checks
  const bringToFront = () => {
    if (activeObject && !objectPosition.isAtFront) {
      activeObject.bringToFront();
      canvas.renderAll();
      const object = canvas.toJSON(['id', 'selectable']); // Include any custom properties you need
      const updateData = { ...projectData?.data, object };
      // Wait for the project update before continuing
      projectUpdate({ id, updateData });
      setIsPopoverOpen(false);
    }
  };

  const sendToBack = () => {
    if (activeObject && !objectPosition.isAtBack) {
      activeObject.sendToBack();
      canvas.renderAll();
      const object = canvas.toJSON(['id', 'selectable']); // Include any custom properties you need
      const updateData = { ...projectData?.data, object };
      // Wait for the project update before continuing
      projectUpdate({ id, updateData });
      setIsPopoverOpen(false);
    }
  };

  const { mutate: deleteMutate } = useMutation({
    mutationFn: async (url) => {
      return await deleteImage(url);
    },
    onSuccess: (data) => {
      if (data?.status === 200) {
        toast({
          title: data?.status,
          description: data?.message
        })
        if (canvas) {
          const object = canvas.toJSON(['id', 'selectable']); // Include any custom properties you need
          const updateData = { ...projectData?.data, object };
          // Wait for the project update before continuing
          projectUpdate({ id, updateData });
        }
      }
      else {
        toast({
          variant: "destructive",
          title: data?.status,
          description: data?.message
        })
      }
    }
  });

  // Remove Selected Element
  const removeSelected = useCallback(() => {
    const activeObject = canvas?.getActiveObject();

    const allObjects = canvas?.getObjects();

    const textObjects = allObjects.filter(
      (obj) =>
        obj.type === "textbox" || obj.type === "text" || obj.type === "i-text"
    );

    if (activeObject) {
      canvas.remove(activeObject);
      setActiveObject(null);
      const object = canvas.toJSON(['id', 'selectable']); // Include any custom properties you need
      const updateData = { ...projectData?.data, object };
      // Wait for the project update before continuing
      projectUpdate({ id, updateData });
    }
    if (activeObject && textObjects?.length === 1) {
      canvas.remove(activeObject);
      setActiveObject(null);
      const object = canvas.toJSON(['id', 'selectable']); // Include any custom properties you need
      const updateData = { ...projectData?.data, object };
      // Wait for the project update before continuing
      projectUpdate({ id, updateData });
    }
    if (activeObject.length > 1) {
      canvas.remove(...activeObject);
      setActiveObject(null);
      const object = canvas.toJSON(['id', 'selectable']); // Include any custom properties you need
      const updateData = { ...projectData?.data, object };
      // Wait for the project update before continuing
      projectUpdate({ id, updateData });
    }

    if (activeObject?.type === "image") {
      const imgUrl = activeObject?._originalElement?.currentSrc;
      canvas.remove(activeObject);
      setActiveObject(null);
      canvas.renderAll();
      deleteMutate(imgUrl);
    }
  }, [canvas, setActiveObject, deleteMutate, id, projectData, projectUpdate]);

  // duplicating current objects
  const duplicating = () => {
    // Clone the active object to create a true deep copy
    activeObject.clone((clonedObject) => {
      // Add the cloned object to the canvas
      clonedObject.set("left", clonedObject?.left + 30);
      canvas.add(clonedObject);
      canvas.renderAll();
      const object = canvas.toJSON(['id', 'selectable']); // Include any custom properties you need
      const updateData = { ...projectData?.data, object };
      // Wait for the project update before continuing
      projectUpdate({ id, updateData });
    });
  };

  // for clear canvas
  const clearCanvas = () => {
    canvas.clear();
    canvas.renderAll();
    canvas.setBackgroundColor("#ffffff", canvas.renderAll.bind(canvas));
    setActiveObject(null);
    const object = canvas.toJSON(['id', 'selectable']); // Include any custom properties you need
    const updateData = { ...projectData?.data, object };
    // Wait for the project update before continuing
    projectUpdate({ id, updateData });
  };

  return (
    <div>
      <TooltipProvider>
        <div
          className={`flex items-center gap-2 ${value === "default"
            ? "space-x-4"
            : "xl:grid-cols-3 lg:grid-cols-3 md:grid-cols-3"
            }`}
        >
          {multipleObjects && (
            <ActionButton
              icon={<GroupIcon className="h-4 w-4" />}
              label="Group"
              onClick={groupSelectedObjects}
              tooltipContent={
                <div className="text-sm">
                  <p className="font-semibold mb-1">Group selected objects</p>
                  <p>To select multiple objects:</p>
                  <ol className="list-decimal list-inside mt-1">
                    <li>Hold down the Shift key</li>
                    <li>
                      Click and drag with the left mouse button to select
                      objects
                    </li>
                    <li>Release the Shift key and mouse button</li>
                  </ol>
                  <p className="mt-1">
                    Then click this button to group the selected objects.
                  </p>
                </div>
              }
            />
          )}

          {isGroupObject && (
            <ActionButton
              icon={<UngroupIcon className="h-4 w-4" />}
              label="Ungroup"
              onClick={ungroupSelectedObjects}
              tooltipContent="Ungroup selected objects"
            />
          )}

          <ActionButton
            icon={<CopyPlus className="h-4 w-4" />}
            label="Duplicate"
            onClick={duplicating}
            tooltipContent="Duplicate selected objects"
          />
          <Popover open={isPopoverOpen} onOpenChange={setIsPopoverOpen}>
            <Tooltip>
              <TooltipTrigger asChild>
                <PopoverTrigger asChild>
                  <Button variant="outline" size="md" className="w-full">
                    <div className="flex items-center gap-1 p-1">
                      <Layers className="h-4 w-4" />
                      <span className="text-[10px] font-bold">Position</span>
                    </div>
                  </Button>
                </PopoverTrigger>
              </TooltipTrigger>
              <TooltipContent side="bottom" align="center">
                <p>Change object position</p>
              </TooltipContent>
            </Tooltip>
            <PopoverContent className="w-40 p-2 z-[9999]">
              <div className="flex flex-col gap-2">
                <Button
                  variant="ghost"
                  size="sm"
                  onClick={bringToFront}
                  disabled={objectPosition.isAtFront}
                >
                  <BringToFront className="h-4 w-4 mr-2" />
                  <span className="text-sm">Bring to Front</span>
                </Button>
                <Button
                  variant="ghost"
                  size="sm"
                  onClick={sendToBack}
                  disabled={objectPosition.isAtBack}
                >
                  <SendToBack className="h-4 w-4 mr-2" />
                  <span className="text-sm">Send to Back</span>
                </Button>
              </div>
            </PopoverContent>
          </Popover>

          <ActionButton
            icon={<Trash2 className="h-4 w-4" />}
            label="Remove"
            onClick={removeSelected}
            tooltipContent="Remove selected objects"
          />

          <ActionButton
            icon={<SquareX className="h-4 w-4" />}
            label="Clear"
            onClick={clearCanvas}
            tooltipContent="Clear entire canvas"
          />
        </div>
      </TooltipProvider>
    </div>
  );
};

function ActionButton({ icon, label, onClick, tooltipContent }) {
  return (
    <Tooltip>
      <TooltipTrigger asChild>
        <Button
          variant="outline"
          size="md"
          className="w-full"
          onClick={onClick}
        >
          <div className="flex items-center gap-1 p-1">
            {icon}
            <span className="text-[10px] font-bold">{label}</span>
          </div>
        </Button>
      </TooltipTrigger>
      <TooltipContent side="bottom" align="center" className="max-w-xs z-[9999]">
        <p>{tooltipContent}</p>
      </TooltipContent>
    </Tooltip>
  );
}
