"use client";

import * as React from "react";

import { cn } from "@/lib/utils";

/*
 * Pinned columns for a table that scrolls sideways (data table spec §1.3; the design system's "Wide table" demo):
 * the first column stays on the left and the last on the right while the middle scrolls. Pinned cells are flat at
 * rest; while the user scrolls sideways a shadow fades in on the side content is passing under, and fades out
 * 400 ms after scrolling stops. Rows need `group/row` so pinned cells follow the row's hover fill.
 */

/** Opaque backgrounds, so scrolled cells never show through a pinned one; they track the row's hover fill. */
const pinBg = "bg-card group-hover/row:bg-[color-mix(in_oklab,var(--muted)_50%,var(--card))] group-data-[state=selected]/row:bg-muted";

export function pinClass(side: "left" | "right", head = false) {
  return cn(
    "sticky",
    head ? "z-30 bg-card" : cn("z-10", pinBg),
    "transition-shadow duration-200",
    side === "left"
      ? "left-0 border-r border-border group-data-[scrolling=true]/scroll:group-data-[scroll-left=true]/scroll:shadow-[10px_0_14px_-8px_rgb(0_17_16/0.28)]"
      : "right-0 border-l border-border group-data-[scrolling=true]/scroll:group-data-[scroll-right=true]/scroll:shadow-[-10px_0_14px_-8px_rgb(0_17_16/0.28)]",
  );
}

/** The scroll container's ref, scroll handler and data attributes that drive the pinned columns' shadows. */
export function usePinnedScroll() {
  const ref = React.useRef<HTMLDivElement>(null);
  const [edges, setEdges] = React.useState({ left: false, right: false });
  const [scrolling, setScrolling] = React.useState(false);
  const lastLeft = React.useRef(0);
  const idle = React.useRef<ReturnType<typeof setTimeout> | null>(null);

  const measure = React.useCallback(() => {
    const el = ref.current;
    if (!el) return;
    const left = el.scrollLeft > 0;
    const right = el.scrollLeft + el.clientWidth < el.scrollWidth - 1;
    setEdges((e) => (e.left === left && e.right === right ? e : { left, right }));
  }, []);

  // Horizontal scrolls only; the shadow stays up while scroll events arrive and fades 400 ms after the last one.
  const onScroll = () => {
    measure();
    const el = ref.current;
    if (!el || el.scrollLeft === lastLeft.current) return;
    lastLeft.current = el.scrollLeft;
    setScrolling(true);
    if (idle.current) clearTimeout(idle.current);
    idle.current = setTimeout(() => setScrolling(false), 400);
  };

  React.useEffect(() => {
    const el = ref.current;
    if (!el) return;
    const ro = new ResizeObserver(measure);
    ro.observe(el);
    measure();
    return () => {
      ro.disconnect();
      if (idle.current) clearTimeout(idle.current);
    };
  }, [measure]);

  return { ref, onScroll, "data-scrolling": scrolling, "data-scroll-left": edges.left, "data-scroll-right": edges.right };
}
