import React, {
  useCallback,
  useEffect,
  useMemo,
  useRef,
  useState,
} from "react";
import gsap from "gsap";
import { Draggable } from "gsap/Draggable";
import { DraggableWidget } from "../2d/DraggableWidget";
import { useWidgetStore } from "../../../../store/useWidgetStore";
import { generateUniqueId } from "../../../../functions/generateUniqueId";
import { useSocketStore } from "../../../../store/builder/store";
import { useParams } from "react-router-dom";
import { arrayMove } from "@dnd-kit/sortable";
import { clamp } from "three/src/math/MathUtils";
import { getUserData } from "../../../../functions/getUserData";
import { useVersionContext } from "../../../builder/version/versionContext";

gsap.registerPlugin(Draggable);


type Side = "top" | "bottom" | "left" | "right";
const GAP = 6;

interface Widget {
  id: string;
  type: string;
  title: string;
  panel: Side;
  data: any;
}

interface PanelProps {
  selectedZone: {
    zoneName: string;
    activeSides: Side[];
    panelOrder: Side[];
    lockedPanels: Side[];
    points: [];
    zoneUuid: string;
    zoneViewPortTarget: number[];
    zoneViewPortPosition: number[];
    widgets: Widget[];
  };
  setSelectedZone: React.Dispatch<React.SetStateAction<any>>;
  hiddenPanels: any;
  setZonesData: React.Dispatch<React.SetStateAction<any>>;
  waitingPanels: any;
}

type SortableItem = {
  dragger: Draggable;
  element: HTMLDivElement;
  index: number;
  setIndex: (idx: number) => void;
};

const Panel: React.FC<PanelProps> = ({
  selectedZone,
  setSelectedZone,
  hiddenPanels,
}) => {
  // const rowSize = 160;
  // const colSize = 160;
  const [rowSize, setRowSize] = useState<number>(160);
  const [colSize, setColSize] = useState<number>(160);
  const [openKebabId, setOpenKebabId] = useState<string | null>(null);
  const [initialItems, setInitialItems] = useState<Widget[]>([]);

  const containerRef = useRef<{ [side in Side]?: HTMLDivElement }>({});
  const itemRefs = useRef<{ [side in Side]?: HTMLDivElement[] }>({});
  const sortables = useRef<{ [side in Side]?: SortableItem[] }>({});
  const draggables = useRef<{ [side in Side]?: Draggable[] }>({});

  const { visualizationSocket } = useSocketStore();
  const [canvasDimensions, setCanvasDimensions] = useState({
    width: 0,
    height: 0,
  });
  const [panelDimensions, setPanelDimensions] = useState<{
    [side in Side]?: { width: number; height: number };
  }>({});
  const { projectId } = useParams();
  const panelRefs = useRef<{ [side in Side]?: HTMLDivElement }>({});
  const { userId, organization, email } = getUserData();
  const { selectedVersionStore } = useVersionContext();
  const { selectedVersion } = selectedVersionStore();

  // function handleResize() {
  //   const canvas = document.getElementById("sceneCanvas");
  //   if (canvas) {
  //     const rect = canvas.getBoundingClientRect(); 
  //     setRowSize(rect.height / 6)
  //     setColSize(rect.width / 6)
  //   }
  // }

  // useEffect(() => {
  //   window.addEventListener("resize", handleResize);
  //   return () => {
  //     window.removeEventListener("resize", handleResize);
  //   };
  // }, []);

  useEffect(() => {
    const observers: ResizeObserver[] = [];
    const currentPanelRefs = panelRefs.current;
    selectedZone.activeSides.forEach((side) => {
      const element = currentPanelRefs[side];
      if (element) {
        const observer = new ResizeObserver((entries) => {
          for (const entry of entries) {
            const { width, height } = entry.contentRect;
            setPanelDimensions((prev) => ({
              ...prev,
              [side]: { width, height },
            }));
          }
        });

        observer.observe(element);
        observers.push(observer);
      }
    });

    return () => {
      observers.forEach((observer) => observer.disconnect());
    };
  }, [selectedZone.activeSides]);
  // Track canvas dimensions

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

    const updateCanvasDimensions = () => {
      const rect = canvas.getBoundingClientRect();
      setCanvasDimensions({
        width: rect.width,
        height: rect.height,
      });
    };

    updateCanvasDimensions();
    const resizeObserver = new ResizeObserver(updateCanvasDimensions);
    resizeObserver.observe(canvas);

    return () => resizeObserver.unobserve(canvas);
  }, []);

  // Calculate panel size
  const panelSize = Math.max(
    Math.min(canvasDimensions.width * 0.25, canvasDimensions.height * 0.25),
    170 // Min 170px
  );
  useEffect(() => {
    setInitialItems(selectedZone.widgets);
  }, [selectedZone]);

  const getPanelStyle = useMemo(
    () => (side: Side) => {
      const currentIndex = selectedZone.panelOrder.indexOf(side);
      const previousPanels = selectedZone.panelOrder.slice(0, currentIndex);
      const leftActive = previousPanels.includes("left");
      const rightActive = previousPanels.includes("right");
      const topActive = previousPanels.includes("top");
      const bottomActive = previousPanels.includes("bottom");

      switch (side) {
        case "top":
        case "bottom":
          return {
            minWidth: "170px",
            width: `calc(100% - ${(leftActive ? panelSize : 0) + (rightActive ? panelSize : 0)
              }px)`,
            minHeight: "170px",
            height: `${panelSize}px`,
            left: leftActive ? `${panelSize}px` : "0",
            right: rightActive ? `${panelSize}px` : "0",
            [side]: "0",
          };
        case "left":
        case "right":
          return {
            minWidth: "170px",
            width: `${panelSize}px`,
            minHeight: "170px",
            height: `calc(100% - ${(topActive ? panelSize : 0) + (bottomActive ? panelSize : 0)
              }px)`,
            top: topActive ? `${panelSize}px` : "0",
            bottom: bottomActive ? `${panelSize}px` : "0",
            [side]: "0",
          };
        default:
          return {};
      }
    },
    [selectedZone.panelOrder, panelSize]
  );
  const handleReorder = (fromIndex: number, toIndex: number, panel: Side) => {
    setSelectedZone((prev: any) => {
      const widgetsInPanel = prev.widgets.filter((w: any) => w.panel === panel);
      const reorderedWidgets = arrayMove(widgetsInPanel, fromIndex, toIndex);
      const updatedWidgets = prev.widgets
        .filter((w: any) => w.panel !== panel)
        .concat(reorderedWidgets);

      return {
        ...prev,
        widgets: updatedWidgets,
      };
    });
    setInitialItems(selectedZone.widgets);
  };

  useEffect(() => { }, [initialItems]);

  let fromIndex = useRef<Number>();
  let toIndex = useRef<Number>();
  let itemsRef = useRef<any>();

  useEffect(() => {
    selectedZone.activeSides.forEach((side) => {
      const container = containerRef.current[side];
      const widgets = initialItems.filter((w) => w.panel === side);
      const itemList = itemRefs.current[side] || [];

      if (!container || widgets.length === 0) return;

      gsap.to(container, { autoAlpha: 1, duration: 0.5 });

      // Cleanup old draggables
      draggables.current[side]?.forEach((d) => d.kill());
      draggables.current[side] = [];
      sortables.current[side] = [];

      widgets.forEach((widget, index) => {
        const element = itemList[index];
        if (!element) return;

        const content = element.querySelector(".item-content") as HTMLElement;
        const order = element.querySelector(".order") as HTMLElement;

        const animation = gsap.to(content, {
          boxShadow: "rgba(0,0,0,0.2) 0px 16px 32px 0px",
          scale: 1.05,
          paused: true,
          duration: 0.25,
        });

        const sortable: SortableItem = {
          dragger: null as any,
          element,
          index,
          setIndex(idx: number) {
            sortable.index = idx;
            if (order) order.textContent = (idx + 1).toString();
          },
        };

        const isHorizontal = side === "top" || side === "bottom";

        const dragger = Draggable.create(element, {
          type: isHorizontal ? "x" : "y",
          cursor: "grab",
          onPress() {
            animation.play();
            this.update();
          },
          onDrag() {
            const pos = isHorizontal ? this.x : this.y;
            const newIndex = clamp(
              Math.round(pos / rowSize),
              0,
              widgets.length - 1
            );
            if (newIndex !== sortable.index) {
              const arr = sortables.current[side]!;
              const movedArr = arrayMove(arr, sortable.index, newIndex);

              sortables.current[side] = movedArr;
              if (newIndex === movedArr.length - 1) {
                container.appendChild(element);
              } else {
                const i = sortable.index > newIndex ? newIndex : newIndex + 1;
                container.insertBefore(element, container.children[i]);
              }

              movedArr.forEach((s, idx) => {
                s.setIndex(idx);
                if (s.element !== element) {
                  gsap.to(s.element, {
                    [isHorizontal ? "x" : "y"]: idx * (isHorizontal ? colSize : rowSize + GAP),
                    duration: 0.25,
                    overwrite: true,
                  });
                }
              });
            }
          },
          onRelease() {
            animation.reverse();
            handleReorder(index, sortable.index, side);

            gsap.to(element, {
              [isHorizontal ? "x" : "y"]: sortable.index * (isHorizontal ? colSize : rowSize + GAP),
              duration: 0.3,
            });

          },
        })[0];

        sortable.dragger = dragger;
        draggables.current[side]?.push(dragger);
        sortables.current[side]?.push(sortable);

        gsap.set(element, {
          [isHorizontal ? "x" : "y"]: index * (isHorizontal ? colSize : rowSize + GAP),
        });

      });
    });

    return () => {
      Object.values(draggables.current).forEach((draggers) => {
        draggers?.forEach((d) => d.kill());
      });
      draggables.current = {};
      sortables.current = {};
    };
  }, [initialItems]);

  const isPanelLocked = (panel: Side) =>
    selectedZone.lockedPanels.includes(panel);

  // Get current widget count in a panel
  const getCurrentWidgetCount = (panel: Side) =>
    selectedZone.widgets.filter((w) => w.panel === panel).length;

  // Calculate panel capacity
  const calculatePanelCapacity = (panel: Side) => {
    const CHART_WIDTH = panelSize - 10;
    const CHART_HEIGHT = panelSize - 10;

    const dimensions = panelDimensions[panel];

    if (!dimensions) {
      return panel === "top" || panel === "bottom" ? 5 : 3; // Fallback capacities
    }

    return panel === "top" || panel === "bottom"
      ? Math.max(1, Math.floor(dimensions.width / CHART_WIDTH))
      : Math.max(1, Math.floor(dimensions.height / CHART_HEIGHT));
  };

  // Add widget to panel
  const addWidgetToPanel = async (asset: any, panel: Side) => {


    const newWidget = {
      ...asset,
      id: generateUniqueId(),
      panel,
    };

    let addWidget = {
      organization,
      zoneUuid: selectedZone.zoneUuid,
      widget: newWidget,
      versionId: selectedVersion?.versionId || '',
      projectId,
      userId,
    };

    if (visualizationSocket) {
      visualizationSocket.emit("v1:viz-widget:add", addWidget);
    }

    setSelectedZone((prev: any) => ({
      ...prev,
      widgets: [...prev.widgets, newWidget],
    }));
  };

  // Handle drop event
  const handleDrop = (e: React.DragEvent, panel: Side) => {
    e.preventDefault();

    const { draggedAsset } = useWidgetStore.getState();
    if (
      !draggedAsset ||
      isPanelLocked(panel) ||
      hiddenPanels[selectedZone.zoneUuid]?.includes(panel)
    )
      return;

    const currentWidgetsCount = getCurrentWidgetCount(panel);
    const maxCapacity = calculatePanelCapacity(panel);

    if (currentWidgetsCount < maxCapacity) {
      addWidgetToPanel(draggedAsset, panel);
    } else {
    }
  };
  const topWidth = getPanelStyle("top").width;
  const bottomWidth = getPanelStyle("bottom").height;
  const leftHeight = getPanelStyle("left").height;
  const rightHeight = getPanelStyle("right").height;

  const topCapacity = calculatePanelCapacity("top");
  const bottomCapacity = calculatePanelCapacity("bottom");
  const leftCapacity = calculatePanelCapacity("left");
  const rightCapacity = calculatePanelCapacity("right");
  return (
    <>
      <style>
        {`
          :root {
            --topWidth: ${topWidth};
            --bottomWidth: ${bottomWidth} ;
            --leftHeight: ${leftHeight};
            --rightHeight: ${rightHeight};
            --topCapacity: ${topCapacity};
            --bottomCapacity: ${bottomCapacity};
            --leftCapacity: ${leftCapacity};
            --rightCapacity: ${rightCapacity};
          }
        `}
      </style>

      {selectedZone.activeSides.map((side) => (
        <div
          style={getPanelStyle(side)}
          onDrop={(e) => handleDrop(e, side)}
          onDragOver={(e) => e.preventDefault()}
          ref={(el) => {
            if (el) {
              panelRefs.current[side] = el;
            } else {
              delete panelRefs.current[side];
            }
          }}
          key={side}
          id={`panel-wrapper-${side}`}
          className={`panel ${side}-panel absolute ${hiddenPanels[selectedZone.zoneUuid]?.includes(side)
            ? "hidePanel"
            : ""
            }`}
        >
          <div
            className="container"
            // ref={containerRef}
            ref={(el) => {
              if (el) containerRef.current[side] = el;
            }}
            style={{ position: "relative", width: "100%" }}
          >
            {initialItems
              .filter((w) => w.panel === side)
              .map((label, index) => (
                <div
                  className="list-item chart-container"
                  key={label.id}
                  data-panel={label.panel}

                  ref={(el) => {
                    if (!itemRefs.current[side]) itemRefs.current[side] = [];
                    if (el) itemRefs.current[side]![index] = el;
                  }}

                  style={{
                    position: "absolute",
                    left: 0,
                    height: ["left", "right"].includes(side) ? rowSize : "",
                    width: ["left", "right"].includes(side) ? "" : colSize,
                    cursor: "grab",
                    userSelect: "none",
                    // marginBottom: side === "left" || side === "right" ? "10px" : "",
                    // marginRight: side === "top" || side === "bottom" ? "10px" : "",
                  }}

                >
                  <DraggableWidget
                    widget={label}
                    index={index}
                    openKebabId={openKebabId}
                    setOpenKebabId={setOpenKebabId}
                  />
                </div>
              ))}
          </div>
        </div>
      ))}
    </>
  );
};

export default Panel;
