import React, { useEffect, useMemo, useRef, useState } from "react";
import { useWidgetStore } from "../../../store/useWidgetStore";
import { usePlayButtonStore } from "../../../store/usePlayButtonStore";
import { DraggableWidget } from "./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[];
    widgets: Widget[];
  };
  setSelectedZone: React.Dispatch<
    React.SetStateAction<{
      zoneName: string;
      activeSides: Side[];
      panelOrder: Side[];
      lockedPanels: Side[];
      widgets: Widget[];
    }>
  >;
  hiddenPanels: string[];
}

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

const Panel: React.FC<PanelProps> = ({
  selectedZone,
  setSelectedZone,
  hiddenPanels,
}) => {
  const panelRefs = useRef<{ [side in Side]?: HTMLDivElement }>({});
  const [panelDimensions, setPanelDimensions] = useState<{
    [side in Side]?: { width: number; height: number };
  }>({});

  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");
      const panelSize = isPlaying ? 355 : 305;

      switch (side) {
        case "top":
        case "bottom":
          return {
            width: `calc(100% - ${
              (leftActive ? panelSize : 0) + (rightActive ? panelSize : 0)
            }px)`,
            height: `${panelSize - 5}px`,
            left: leftActive ? `${panelSize}px` : "0",
            right: rightActive ? `${panelSize}px` : "0",
            [side]: "0",
          };
        case "left":
        case "right":
          return {
            width: `${panelSize - 5}px`,
            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]
  );

  const handleDrop = (e: React.DragEvent, panel: Side) => {
    e.preventDefault();
    const { draggedAsset } = useWidgetStore.getState();
    if (!draggedAsset) return;
    if (isPanelLocked(panel)) return;

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

    if (currentWidgetsCount >= maxCapacity) return;

    addWidgetToPanel(draggedAsset, panel);
  };

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

  const getCurrentWidgetCount = (panel: Side) =>
    selectedZone.widgets.filter((w) => w.panel === panel).length;

  const calculatePanelCapacity = (panel: Side) => {
    const CHART_WIDTH = 250;
    const CHART_HEIGHT = 250;
    const FALLBACK_HORIZONTAL_CAPACITY = 5;
    const FALLBACK_VERTICAL_CAPACITY = 3;

    const dimensions = panelDimensions[panel];
    if (!dimensions) {
      return panel === "top" || panel === "bottom"
        ? FALLBACK_HORIZONTAL_CAPACITY
        : FALLBACK_VERTICAL_CAPACITY;
    }

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

  const addWidgetToPanel = (asset: any, panel: Side) => {
    const newWidget = {
      ...asset,
      id: generateUniqueId(),
      panel,
    };

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

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

  const { isPlaying } = usePlayButtonStore();

  return (
    <>
      {selectedZone.activeSides.map((side) => (
        <div
          key={side}
          className={`panel ${side}-panel absolute ${isPlaying && ""}`}
          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 ${isPlaying && "fullScreen"}`}
            style={{
              pointerEvents: selectedZone.lockedPanels.includes(side)
                ? "none"
                : "auto",
              opacity: selectedZone.lockedPanels.includes(side) ? "0.8" : "1",
            }}
          >
            {selectedZone.widgets
              .filter((w) => w.panel === side)
              .map((widget) => (
                <DraggableWidget
                  hiddenPanels={hiddenPanels}
                  widget={widget}
                  key={widget.id}
                />
              ))}
          </div>
        </div>
      ))}
    </>
  );
};

export default Panel;
