"use client";

import * as React from "react";
import { cn } from "~/lib/utils";
import { Sheet, SheetContent, SheetTrigger } from "~/components/ui/sheet";
import { Button } from "~/components/ui/button";
import { PanelLeft, Settings2 } from "lucide-react";
type Edge = "left" | "right";

export interface PanelsContainerProps {
  left?: React.ReactNode;
  center: React.ReactNode;
  right?: React.ReactNode;

  /**
   * Draw dividers between panels (applied to center only to avoid double borders).
   * Defaults to true.
   */
  showDividers?: boolean;

  /** Class applied to the root container */
  className?: string;

  /** Class applied to each panel wrapper (left/center/right) */
  panelClassName?: string;

  /** Class applied to each panel's internal scroll container */
  contentClassName?: string;

  /** Accessible label for the overall layout */
  "aria-label"?: string;

  /** Min/Max fractional widths for left and right panels (0..1), clamped during drag */
  minLeftPct?: number;
  maxLeftPct?: number;
  minRightPct?: number;
  maxRightPct?: number;

  /** Keyboard resize step (fractional) per arrow press; Shift increases by 2x */
  keyboardStepPct?: number;

  /**
   * Controlled collapse state
   */
  leftCollapsed?: boolean;
  rightCollapsed?: boolean;
  onLeftCollapseChange?: (collapsed: boolean) => void;
  onRightCollapseChange?: (collapsed: boolean) => void;
}

/**
 * PanelsContainer
 *
 * Tailwind-first, grid-based panel layout with:
 * - Drag-resizable left/right panels (no persistence)
 * - Collapsible side panels
 * - Strict overflow containment (no page-level x-scroll)
 * - Internal y-scroll for each panel
 * - Optional visual dividers on the center panel only (prevents double borders)
 *
 * Implementation details:
 * - Uses CSS variables for column fractions and an explicit grid template:
 *   [minmax(0,var(--col-left)) minmax(0,var(--col-center)) minmax(0,var(--col-right))]
 * - Resize handles are absolutely positioned over the grid at the left and right boundaries.
 * - Fractions are clamped with configurable min/max so panels remain usable at all sizes.
 */
const Panel: React.FC<
  React.PropsWithChildren<{
    className?: string;
    panelClassName?: string;
    contentClassName?: string;
  }>
> = ({ className: panelCls, panelClassName, contentClassName, children }) => (
  <section
    className={cn(
      "min-w-0 overflow-hidden transition-[width,opacity] duration-300 ease-in-out",
      panelCls,
      panelClassName,
    )}
  >
    <div
      className={cn(
        "h-full min-h-0 w-full overflow-x-hidden overflow-y-auto",
        contentClassName,
      )}
    >
      {children}
    </div>
  </section>
);

export function PanelsContainer({
  left,
  center,
  right,
  showDividers = true,
  className,
  panelClassName,
  contentClassName,
  "aria-label": ariaLabel = "Designer panel layout",
  minLeftPct = 0.12,
  maxLeftPct = 0.33,
  minRightPct = 0.12,
  maxRightPct = 0.33,
  keyboardStepPct = 0.02,
  leftCollapsed = false,
  rightCollapsed = false,
  onLeftCollapseChange,
  onRightCollapseChange,
}: PanelsContainerProps) {
  const hasLeft = Boolean(left);
  const hasRight = Boolean(right);
  const hasCenter = Boolean(center);

  // Fractions for side panels (center is derived as 1 - (left + right))
  const [leftPct, setLeftPct] = React.useState<number>(hasLeft ? 0.2 : 0);
  const [rightPct, setRightPct] = React.useState<number>(hasRight ? 0.24 : 0);

  const rootRef = React.useRef<HTMLDivElement | null>(null);
  const dragRef = React.useRef<{
    edge: Edge;
    startX: number;
    startLeft: number;
    startRight: number;
    containerWidth: number;
  } | null>(null);

  const clamp = (v: number, lo: number, hi: number): number =>
    Math.max(lo, Math.min(hi, v));

  const recompute = React.useCallback(
    (lp: number, rp: number) => {
      if (!hasCenter) return { l: 0, c: 0, r: 0 };

      // Effective widths (0 if collapsed)
      const effectiveL = leftCollapsed ? 0 : lp;
      const effectiveR = rightCollapsed ? 0 : rp;

      // When logic runs, we must clamp the *underlying* percentages (lp, rp)
      // but return 0 for the CSS vars if collapsed.

      // Actually, if collapsed, we just want the CSS var to be 0.
      // But we maintain the state `leftPct` so it restores correctly.

      if (hasLeft && hasRight) {
        // Standard clamp (on the state values)
        const lState = clamp(lp, minLeftPct, maxLeftPct);
        const rState = clamp(rp, minRightPct, maxRightPct);

        // Effective output
        const l = leftCollapsed ? 0 : lState;
        const r = rightCollapsed ? 0 : rState;

        // Center takes remainder
        const c = 1 - (l + r);
        return { l, c, r };
      }
      if (hasLeft && !hasRight) {
        const lState = clamp(lp, minLeftPct, maxLeftPct);
        const l = leftCollapsed ? 0 : lState;
        const c = 1 - l;
        return { l, c, r: 0 };
      }
      if (!hasLeft && hasRight) {
        const rState = clamp(rp, minRightPct, maxRightPct);
        const r = rightCollapsed ? 0 : rState;
        const c = 1 - r;
        return { l: 0, c, r };
      }
      // Center only
      return { l: 0, c: 1, r: 0 };
    },
    [
      hasCenter,
      hasLeft,
      hasRight,
      minLeftPct,
      maxLeftPct,
      minRightPct,
      maxRightPct,
      leftCollapsed,
      rightCollapsed,
    ],
  );

  const { l, c, r } = recompute(leftPct, rightPct);

  // Attach/detach global pointer handlers safely
  const onPointerMove = React.useCallback(
    (e: PointerEvent) => {
      const d = dragRef.current;
      if (!d || d.containerWidth <= 0) return;

      const deltaPx = e.clientX - d.startX;
      const deltaPct = deltaPx / d.containerWidth;

      if (d.edge === "left" && hasLeft && !leftCollapsed) {
        const nextLeft = clamp(d.startLeft + deltaPct, minLeftPct, maxLeftPct);
        setLeftPct(nextLeft);
      } else if (d.edge === "right" && hasRight && !rightCollapsed) {
        // Dragging the right edge moves leftwards as delta increases
        const nextRight = clamp(
          d.startRight - deltaPct,
          minRightPct,
          maxRightPct,
        );
        setRightPct(nextRight);
      }
    },
    [
      hasLeft,
      hasRight,
      minLeftPct,
      maxLeftPct,
      minRightPct,
      maxRightPct,
      leftCollapsed,
      rightCollapsed,
    ],
  );

  const endDrag = React.useCallback(() => {
    dragRef.current = null;
    window.removeEventListener("pointermove", onPointerMove);
    window.removeEventListener("pointerup", endDrag);
  }, [onPointerMove]);

  const startDrag =
    (edge: Edge) => (e: React.PointerEvent<HTMLButtonElement>) => {
      if (!rootRef.current) return;
      e.preventDefault();

      const rect = rootRef.current.getBoundingClientRect();
      dragRef.current = {
        edge,
        startX: e.clientX,
        startLeft: leftPct,
        startRight: rightPct,
        containerWidth: rect.width,
      };

      window.addEventListener("pointermove", onPointerMove);
      window.addEventListener("pointerup", endDrag);
    };

  React.useEffect(() => {
    return () => {
      // Cleanup if unmounted mid-drag
      window.removeEventListener("pointermove", onPointerMove);
      window.removeEventListener("pointerup", endDrag);
    };
  }, [onPointerMove, endDrag]);

  // Keyboard resize for handles
  const onKeyResize =
    (edge: Edge) => (e: React.KeyboardEvent<HTMLButtonElement>) => {
      if (e.key !== "ArrowLeft" && e.key !== "ArrowRight") return;
      e.preventDefault();

      const step = (e.shiftKey ? 2 : 1) * keyboardStepPct;

      if (edge === "left" && hasLeft && !leftCollapsed) {
        const next = clamp(
          leftPct + (e.key === "ArrowRight" ? step : -step),
          minLeftPct,
          maxLeftPct,
        );
        setLeftPct(next);
      } else if (edge === "right" && hasRight && !rightCollapsed) {
        const next = clamp(
          rightPct + (e.key === "ArrowLeft" ? step : -step),
          minRightPct,
          maxRightPct,
        );
        setRightPct(next);
      }
    };

  // CSS variables for the grid fractions
  // We use FR units instead of % to let the browser handle exact pixel fitting without rounding errors causing overflow
  const styleVars: React.CSSProperties & Record<string, string> = hasCenter
    ? {
        "--col-left": `${hasLeft ? l : 0}fr`,
        "--col-center": `${c}fr`,
        "--col-right": `${hasRight ? r : 0}fr`,
      }
    : {};

  // Explicit grid template depending on which side panels exist
  const gridAreas =
    hasLeft && hasRight
      ? '"left center right"'
      : hasLeft && !hasRight
        ? '"left center"'
        : !hasLeft && hasRight
          ? '"center right"'
          : '"center"';

  const gridCols =
    hasLeft && hasRight
      ? "[grid-template-columns:var(--col-left)_var(--col-center)_var(--col-right)]"
      : hasLeft && !hasRight
        ? "[grid-template-columns:var(--col-left)_var(--col-center)]"
        : !hasLeft && hasRight
          ? "[grid-template-columns:var(--col-center)_var(--col-right)]"
          : "[grid-template-columns:1fr]";

  // Dividers on the center panel only (prevents double borders if children have their own borders)
  const centerDividers =
    showDividers && hasCenter
      ? cn({
          "border-l": hasLeft,
          "border-r": hasRight,
        })
      : undefined;

  return (
    <>
      {/* Mobile Layout (Flex + Sheets) */}
      <div className={cn("flex h-full w-full flex-col md:hidden", className)}>
        {/* Mobile Header/Toolbar for access to panels */}
        <div className="bg-background flex items-center justify-between border-b px-4 py-2">
          <div className="flex items-center gap-2">
            {hasLeft && (
              <Sheet>
                <SheetTrigger asChild>
                  <Button variant="outline" size="icon" className="h-8 w-8">
                    <PanelLeft className="h-4 w-4" />
                  </Button>
                </SheetTrigger>
                <SheetContent side="left" className="w-[85vw] p-0 sm:max-w-md">
                  <div className="h-full overflow-hidden">{left}</div>
                </SheetContent>
              </Sheet>
            )}
            <span className="text-sm font-medium">Designer</span>
          </div>

          {hasRight && (
            <Sheet>
              <SheetTrigger asChild>
                <Button variant="outline" size="icon" className="h-8 w-8">
                  <Settings2 className="h-4 w-4" />
                </Button>
              </SheetTrigger>
              <SheetContent side="right" className="w-[85vw] p-0 sm:max-w-md">
                <div className="h-full overflow-hidden">{right}</div>
              </SheetContent>
            </Sheet>
          )}
        </div>

        {/* Main Content (Center) */}
        <div className="relative min-h-0 min-w-0 flex-1 overflow-hidden">
          {center}
        </div>
      </div>

      {/* Desktop Layout (Grid) */}
      <div
        ref={rootRef}
        aria-label={ariaLabel}
        className={cn(
          "relative hidden h-full min-h-0 w-full max-w-full overflow-hidden select-none md:grid",
          // 2-3-2 ratio for left-center-right panels when all visible
          hasLeft &&
            hasRight &&
            !leftCollapsed &&
            !rightCollapsed &&
            "grid-cols-[2fr_3fr_2fr]",
          // Left collapsed: center + right (3:2 ratio)
          hasLeft &&
            hasRight &&
            leftCollapsed &&
            !rightCollapsed &&
            "grid-cols-[3fr_2fr]",
          // Right collapsed: left + center (2:3 ratio)
          hasLeft &&
            hasRight &&
            !leftCollapsed &&
            rightCollapsed &&
            "grid-cols-[2fr_3fr]",
          // Both collapsed: center only
          hasLeft &&
            hasRight &&
            leftCollapsed &&
            rightCollapsed &&
            "grid-cols-1",
          // Only left and center
          hasLeft && !hasRight && !leftCollapsed && "grid-cols-[2fr_3fr]",
          hasLeft && !hasRight && leftCollapsed && "grid-cols-1",
          // Only center and right
          !hasLeft && hasRight && !rightCollapsed && "grid-cols-[3fr_2fr]",
          !hasLeft && hasRight && rightCollapsed && "grid-cols-1",
          // Only center
          !hasLeft && !hasRight && "grid-cols-1",
          className,
        )}
      >
        {hasLeft && !leftCollapsed && (
          <Panel
            panelClassName={panelClassName}
            contentClassName={contentClassName}
          >
            {left}
          </Panel>
        )}

        {hasCenter && (
          <Panel
            className={centerDividers}
            panelClassName={panelClassName}
            contentClassName={contentClassName}
          >
            {center}
          </Panel>
        )}

        {hasRight && !rightCollapsed && (
          <Panel
            panelClassName={panelClassName}
            contentClassName={contentClassName}
          >
            {right}
          </Panel>
        )}

        {/* Resize Handles */}
        {hasLeft && !leftCollapsed && (
          <button
            type="button"
            className="absolute top-0 bottom-0 z-50 -ml-0.75 w-1.5 cursor-col-resize transition-colors hover:bg-blue-400/50 focus:outline-none"
            style={{ left: "var(--col-left)" }}
            onPointerDown={startDrag("left")}
            onKeyDown={onKeyResize("left")}
            aria-label="Resize left panel"
          />
        )}
        {hasRight && !rightCollapsed && (
          <button
            type="button"
            className="absolute top-0 bottom-0 z-50 -mr-0.75 w-1.5 cursor-col-resize transition-colors hover:bg-blue-400/50 focus:outline-none"
            style={{ right: "var(--col-right)" }}
            onPointerDown={startDrag("right")}
            onKeyDown={onKeyResize("right")}
            aria-label="Resize right panel"
          />
        )}
      </div>
    </>
  );
}

export default PanelsContainer;
