"use client";

import * as React from "react";

import { Button } from "@/components/ui/button";
import {
  Tooltip,
  TooltipContent,
  TooltipTrigger,
} from "@/components/ui/tooltip";
import { cn } from "@/lib/utils";

import type { DataTableRowAction } from "./types";

/** How long (ms) a touch must be held before the tooltip is revealed */
const LONG_PRESS_MS = 400;

/**
 * Per-row actions rendered as inline icon buttons (no dropdown). Each label is
 * shown as a tooltip: on hover for pointer devices, and on long-press for touch
 * (a plain tap runs the action). Destructive actions render in red.
 *
 * The label comes through as the action's already-translated `label`; it is used
 * both as the tooltip text and the icon button's accessible name. An action
 * without an `icon` falls back to a compact text button so it stays reachable.
 */
function RowActions<TRow>({
  row,
  actions,
}: {
  row: TRow;
  actions: DataTableRowAction<TRow>[];
}) {
  if (actions.length === 0) return null;

  return (
    <div className="flex items-center justify-end gap-1">
      {actions.map((action) => (
        <RowActionButton key={action.key} row={row} action={action} />
      ))}
    </div>
  );
}

function RowActionButton<TRow>({
  row,
  action,
}: {
  row: TRow;
  action: DataTableRowAction<TRow>;
}) {
  // Controlled so touch long-press can reveal the tooltip; hover/focus on
  // pointer devices still drives it through `onOpenChange`.
  const [open, setOpen] = React.useState(false);
  const longPressTimer = React.useRef<ReturnType<typeof setTimeout> | null>(
    null,
  );
  // A long-press must reveal the tooltip WITHOUT also firing the action.
  const suppressClick = React.useRef(false);
  // Remembers the last pointer so `onOpenChange` can ignore touch-driven opens
  // (a tap should act, not flash the tooltip) while allowing mouse hover.
  const lastPointerType = React.useRef<string>("mouse");

  React.useEffect(
    () => () => {
      if (longPressTimer.current) clearTimeout(longPressTimer.current);
    },
    [],
  );

  function clearLongPress() {
    if (longPressTimer.current) {
      clearTimeout(longPressTimer.current);
      longPressTimer.current = null;
    }
  }

  function handlePointerDown(event: React.PointerEvent) {
    lastPointerType.current = event.pointerType;
    // Pointer devices use hover for the tooltip; only touch needs long-press.
    if (event.pointerType !== "touch") return;
    suppressClick.current = false;
    clearLongPress();
    longPressTimer.current = setTimeout(() => {
      suppressClick.current = true;
      setOpen(true);
    }, LONG_PRESS_MS);
  }

  function endPress() {
    clearLongPress();
    // Fallback dismissal so a long-press tooltip can't get stuck open on touch.
    if (suppressClick.current) {
      setTimeout(() => setOpen(false), 600);
    }
  }

  function handleClick() {
    if (suppressClick.current) {
      // The gesture was a long-press (tooltip peek) — swallow the trailing tap.
      suppressClick.current = false;
      return;
    }
    action.onSelect(row);
  }

  const label = action.label;

  return (
    <Tooltip
      open={open}
      onOpenChange={(next) => {
        // Ignore hover/focus opens originating from touch — long-press owns those.
        if (next && lastPointerType.current === "touch") return;
        setOpen(next);
      }}
    >
      <TooltipTrigger
        render={
          <Button
            variant="ghost"
            size="icon-sm"
            disabled={action.disabled}
            aria-label={typeof label === "string" ? label : undefined}
            className={cn(
              action.destructive &&
                "text-destructive hover:bg-destructive/10 hover:text-destructive",
            )}
            onPointerDown={handlePointerDown}
            onPointerUp={endPress}
            onPointerLeave={endPress}
            onPointerCancel={endPress}
            onClick={handleClick}
          />
        }
      >
        {action.icon ?? label}
      </TooltipTrigger>
      <TooltipContent>{label}</TooltipContent>
    </Tooltip>
  );
}

export { RowActions };
