import React, { useEffect, useMemo, useRef, useState } from "react";

import { arrayMove } from "@dnd-kit/sortable";
import { useAsset3dWidget, useSocketStore } from "../../../../store/builder/store";
import { usePlayButtonStore } from "../../../../store/usePlayButtonStore";
import { useWidgetStore } from "../../../../store/useWidgetStore";
import { DraggableWidget } from "../2d/DraggableWidget";

type Side = "top" | "bottom" | "left" | "right";

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

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

const generateUniqueId = () =>
  `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;

const Panel: React.FC<PanelProps> = ({
  selectedZone,
  setSelectedZone,
  hiddenPanels,
  setZonesData,
  waitingPanels,
}) => {
  const { widgetSelect, setWidgetSelect } = useAsset3dWidget();
  const panelRefs = useRef<{ [side in Side]?: HTMLDivElement }>({});
  const [panelDimensions, setPanelDimensions] = useState<{
    [side in Side]?: { width: number; height: number };
  }>({});
  const [openKebabId, setOpenKebabId] = useState<string | null>(null);
  const { isPlaying } = usePlayButtonStore();
  const { visualizationSocket } = useSocketStore();
  const [canvasDimensions, setCanvasDimensions] = useState({
    width: 0,
    height: 0,
  });

  // 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
  );

  // Define getPanelStyle
  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]
  );

  // Handle drop event
  const handleDrop = (e: React.DragEvent, panel: Side) => {
    e.preventDefault();
    const { draggedAsset } = useWidgetStore.getState();
    if (
      !draggedAsset ||
      isPanelLocked(panel) ||
      hiddenPanels[selectedZone.zoneId]?.includes(panel)
    )
      return;

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

    if (currentWidgetsCount < maxCapacity) {
      addWidgetToPanel(draggedAsset, panel);
    }
  };

  // Check if panel is locked
  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 email = localStorage.getItem("email") || "";
    const organization = email?.split("@")[1]?.split(".")[0];

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

    let addWidget = {
      organization: organization,
      zoneId: selectedZone.zoneId,
      widget: newWidget,
    };

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

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

  // Observe panel dimensions
  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]);

  // Handle widget reordering
  const handleReorder = (fromIndex: number, toIndex: number, panel: Side) => {
    setSelectedZone((prev) => {
      const widgetsInPanel = prev.widgets.filter((w) => w.panel === panel);
      const reorderedWidgets = arrayMove(widgetsInPanel, fromIndex, toIndex);

      const updatedWidgets = prev.widgets
        .filter((widget) => widget.panel !== panel)
        .concat(reorderedWidgets);

      return {
        ...prev,
        widgets: updatedWidgets,
      };
    });
  };

  // Calculate capacities and dimensions
  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
          key={side}
          id="panel-wrapper"
          className={`panel ${side}-panel absolute ${
            hiddenPanels[selectedZone.zoneId]?.includes(side) ? "hidePanel" : ""
          }`}
          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];
            }
          }}
        >
          <div
            className={`panel-content
  ${waitingPanels === side ? `${side}-closing` : ""}
  ${
    !hiddenPanels[selectedZone.zoneId]?.includes(side) && waitingPanels !== side
      ? `${side}-opening`
      : ""
  }
  ${isPlaying ? "fullScreen" : ""}`}
            style={{
              pointerEvents:
                selectedZone.lockedPanels.includes(side) ||
                hiddenPanels[selectedZone.zoneId]?.includes(side)
                  ? "none"
                  : "auto",
              opacity: selectedZone.lockedPanels.includes(side) ? "0.8" : "1",
            }}
          >
            {selectedZone.widgets
              .filter((w) => w.panel === side)
              .map((widget, index) => (
                <DraggableWidget
                  hiddenPanels={hiddenPanels}
                  widget={widget}
                  key={widget.id}
                  index={index}
                  onReorder={(fromIndex, toIndex) =>
                    handleReorder(fromIndex, toIndex, side)
                  }
                  openKebabId={openKebabId}
                  setOpenKebabId={setOpenKebabId}
                  selectedZone={selectedZone}
                  setSelectedZone={setSelectedZone}
                />
              ))}
          </div>
        </div>
      ))}
    </>
  );
};

export default Panel;
