import { cn } from "@/lib/utils";
import * as React from "react";
import {
  SortDirection,
  TableSortContext,
  TableSortContextValue,
} from "./tableSortContext";
import { useSortableHeadPresenter } from "./useSortableHeadPresenter";

export type { SortDirection };

export function Table({
  className,
  ...props
}: React.HTMLAttributes<HTMLTableElement>) {
  return (
    <div className="relative w-full overflow-auto rounded-xl border border-stroke/70 bg-white dark:border-dark-3 dark:bg-dark-2">
      <table
        className={cn("w-full caption-bottom text-sm", className)}
        {...props}
      />
    </div>
  );
}

/**
 * Provides the active `sort_by` / `sort_order` state to any `TableHead`
 * rendered with `sortable`. Wrap a `<Table>` with this to enable server-driven
 * column sorting (see `bp-panel-list-sorting.md`).
 */
export function TableSortProvider({
  children,
  ...value
}: TableSortContextValue & { children: React.ReactNode }) {
  const memoizedValue = React.useMemo<TableSortContextValue>(
    () => ({
      sortKey: value.sortKey,
      sortOrder: value.sortOrder,
      onSortChange: value.onSortChange,
    }),
    [value.sortKey, value.sortOrder, value.onSortChange],
  );

  return (
    <TableSortContext.Provider value={memoizedValue}>
      {children}
    </TableSortContext.Provider>
  );
}

export function TableHeader({
  className,
  ...props
}: React.HTMLAttributes<HTMLTableSectionElement>) {
  return (
    <thead
      className={cn(
        "bg-gray-2/60 dark:bg-dark-3/40 [&_tr]:border-b [&_tr]:border-stroke/70 dark:[&_tr]:border-dark-3",
        className,
      )}
      {...props}
    />
  );
}

export const TableBody = React.forwardRef<
  HTMLTableSectionElement,
  React.HTMLAttributes<HTMLTableSectionElement>
>(({ className, ...props }, ref) => (
  <tbody
    ref={ref}
    className={cn("[&_tr:last-child]:border-0 [&_tr]:border-stroke/60 dark:[&_tr]:border-dark-3", className)}
    {...props}
  />
));
TableBody.displayName = "TableBody";

export function TableFooter({
  className,
  ...props
}: React.HTMLAttributes<HTMLTableSectionElement>) {
  return (
    <tfoot
      className={cn(
        "border-t border-stroke/70 bg-gray-2/60 font-medium dark:border-dark-3 dark:bg-dark-3/40 [&>tr]:last:border-b-0",
        className,
      )}
      {...props}
    />
  );
}

export const TableRow = React.forwardRef<
  HTMLTableRowElement,
  React.HTMLAttributes<HTMLTableRowElement>
>(({ className, ...props }, ref) => {
  return (
    <tr
      ref={ref}
      className={cn(
        "border-b transition-colors duration-150 hover:bg-gray-2/60 data-[state=selected]:bg-gray-2 dark:border-dark-3 dark:hover:bg-dark-3/60 dark:data-[state=selected]:bg-dark-3/70",
        className,
      )}
      {...props}
    />
  );
});
TableRow.displayName = "TableRow";

const tableHeadBaseClasses =
  "h-13 px-4 text-left align-middle text-[11px] font-semibold uppercase tracking-[0.08em] text-dark-5 dark:text-dark-6 [&:has([role=checkbox])]:pr-0";

interface TableHeadProps
  extends React.ThHTMLAttributes<HTMLTableCellElement> {
  /** When set, renders an interactive, animated sort control. */
  sortable?: boolean;
  /** BSON field name sent as `sort_by` (e.g. `created_at`). */
  sortKey?: string;
  /** Direction requested on the first click of an inactive column. */
  defaultSortOrder?: SortDirection;
}

export function TableHead({
  className,
  sortable,
  sortKey,
  defaultSortOrder,
  ...props
}: TableHeadProps) {
  if (sortable && sortKey) {
    return (
      <SortableTableHead
        className={className}
        sortKey={sortKey}
        defaultSortOrder={defaultSortOrder}
        {...props}
      />
    );
  }

  return <th className={cn(tableHeadBaseClasses, className)} {...props} />;
}

function Chevron({
  direction,
  className,
}: {
  direction: "up" | "down";
  className?: string;
}) {
  return (
    <svg
      width="11"
      height="7"
      viewBox="0 0 12 8"
      fill="none"
      aria-hidden="true"
      className={cn("block", className)}
    >
      <path
        d={direction === "up" ? "M1.5 6.5L6 2L10.5 6.5" : "M1.5 1.5L6 6L10.5 1.5"}
        stroke="currentColor"
        strokeWidth="2"
        strokeLinecap="round"
        strokeLinejoin="round"
      />
    </svg>
  );
}

function SortableTableHead({
  className,
  sortKey,
  defaultSortOrder = "desc",
  children,
  ...props
}: Omit<TableHeadProps, "sortable"> & { sortKey: string }) {
  const {
    rootRef,
    pillRef,
    upRef,
    downRef,
    sweepRef,
    isActive,
    currentOrder,
    handleClick,
  } = useSortableHeadPresenter(sortKey, defaultSortOrder);

  return (
    <th
      className={cn(tableHeadBaseClasses, "select-none", className)}
      aria-sort={
        isActive
          ? currentOrder === "asc"
            ? "ascending"
            : "descending"
          : "none"
      }
      {...props}
    >
      <button
        ref={rootRef}
        type="button"
        onClick={handleClick}
        className={cn(
          "group/sort -mx-1 inline-flex items-center gap-1.5 rounded-md px-1 py-0.5 align-middle uppercase tracking-[0.08em] outline-none transition-colors duration-200 focus-visible:ring-2 focus-visible:ring-primary/40",
          isActive
            ? "text-primary"
            : "text-dark-5 hover:text-dark dark:text-dark-6 dark:hover:text-white",
        )}
      >
        <span className="whitespace-nowrap">{children}</span>
        <span
          ref={pillRef}
          className={cn(
            "relative inline-flex h-5 w-5 shrink-0 items-center justify-center overflow-hidden rounded-md transition-colors duration-200",
            isActive
              ? "bg-primary/10 dark:bg-primary/15"
              : "bg-transparent group-hover/sort:bg-gray-2 dark:group-hover/sort:bg-dark-3",
          )}
        >
          <span
            ref={sweepRef}
            className="pointer-events-none absolute inset-y-0 -inset-x-2 bg-gradient-to-r from-transparent via-primary/50 to-transparent opacity-0"
          />
          <span className="relative flex flex-col items-center justify-center gap-[1px] leading-none">
            <span ref={upRef} className="block">
              <Chevron direction="up" />
            </span>
            <span ref={downRef} className="block">
              <Chevron direction="down" />
            </span>
          </span>
        </span>
      </button>
    </th>
  );
}

export function TableCell({
  className,
  ...props
}: React.TdHTMLAttributes<HTMLTableCellElement>) {
  return (
    <td
      className={cn(
        "p-4 align-middle text-dark dark:text-white [&:has([role=checkbox])]:pr-0",
        className,
      )}
      {...props}
    />
  );
}
