import type { MouseEvent } from 'react';
import type { Torrent } from './shared';
import type { ColumnDef, ColumnKey } from './columns';
import type { SortKey } from './useTorrentFilters';
import { useRef } from 'react';
import { useVirtualizer } from '@tanstack/react-virtual';
import { ArrowDown, ArrowUp, Check } from 'lucide-react';
import { ContextMenu, ContextMenuContent, ContextMenuItem, ContextMenuTrigger } from '@/components/ui/context-menu';
import { ALL_COLUMNS, PINNED_COLUMN } from './columns';

// The torrent list. Virtualised because the row count is unbounded and the whole thing re-renders on a
// 5-second poll — 43 rows is fine, 4000 is not, and a torrent client accumulates.
//
// Layout is a fixed-width grid inside a single horizontal scroller shared by the header and the body, so
// the two cannot drift apart the way two independently-scrolled elements do.

const ROW_HEIGHT = 30;

type TorrentTableProps = {
  torrents: Torrent[];
  columns: ColumnDef[];
  /** Multi-selection, for the bulk actions in the toolbar and the row context menu. */
  selection: Set<number>;
  /** The one torrent whose detail pane is open (?selected=) — a different thing from being in `selection`. */
  focused: number | null;
  onRowClick: (torrent: Torrent, ev: MouseEvent) => void;
  sort: SortKey;
  desc: boolean;
  onSort: (key: SortKey) => void;
  visibleKeys: ColumnKey[];
  onToggleColumn: (key: ColumnKey) => void;
  onResetColumns: () => void;
  /** Right-clicking a row selects it if it isn't already, then opens the actions menu. */
  onRowContextMenu: (torrent: Torrent) => void;
  rowMenu: (torrent: Torrent) => React.ReactNode;
};

export const TorrentTable = ({
  torrents,
  columns,
  selection,
  focused,
  onRowClick,
  sort,
  desc,
  onSort,
  visibleKeys,
  onToggleColumn,
  onResetColumns,
  onRowContextMenu,
  rowMenu,
}: TorrentTableProps) => {
  const scrollRef = useRef<HTMLDivElement>(null);

  const virtualizer = useVirtualizer({
    count: torrents.length,
    getScrollElement: () => scrollRef.current,
    estimateSize: () => ROW_HEIGHT,
    overscan: 12,
  });

  const gridTemplate = columns.map((c) => `${c.width}px`).join(' ');
  const totalWidth = columns.reduce((sum, c) => sum + c.width, 0);

  return (
    <div ref={scrollRef} className="h-full overflow-auto">
      {/* min-w on an inline-block wrapper: the header must be as wide as the widest row so it keeps
          scrolling with the body rather than clipping at the viewport edge. */}
      <div style={{ minWidth: totalWidth }}>
        <ContextMenu>
          <ContextMenuTrigger asChild>
            <div
              className="sticky top-0 z-10 grid border-b border-border bg-background/95 backdrop-blur"
              style={{ gridTemplateColumns: gridTemplate }}
            >
              {columns.map((col) => (
                <button
                  key={col.key}
                  type="button"
                  disabled={!col.sortKey}
                  onClick={() => col.sortKey && onSort(col.sortKey)}
                  className={`flex items-center gap-1 overflow-hidden px-2 py-1.5 text-[11px] font-medium uppercase tracking-wide text-muted-foreground ${
                    col.sortKey ? 'hover:text-foreground' : 'cursor-default'
                  } ${col.align === 'right' ? 'justify-end' : col.align === 'center' ? 'justify-center' : ''}`}
                >
                  <span className="truncate">{col.label}</span>
                  {col.sortKey === sort &&
                    (desc ? <ArrowDown className="h-3 w-3 shrink-0" /> : <ArrowUp className="h-3 w-3 shrink-0" />)}
                </button>
              ))}
            </div>
          </ContextMenuTrigger>
          <ContextMenuContent className="max-h-[70vh] w-56 overflow-y-auto">
            {ALL_COLUMNS.map((col) => {
              const shown = visibleKeys.includes(col.key);
              const pinned = col.key === PINNED_COLUMN;
              return (
                <ContextMenuItem
                  key={col.key}
                  disabled={pinned}
                  onSelect={(ev) => {
                    // Keep the menu open — picking columns is a several-clicks job and reopening it each
                    // time, at the same mouse position, is a small torture.
                    ev.preventDefault();
                    onToggleColumn(col.key);
                  }}
                >
                  <Check className={`mr-2 h-3.5 w-3.5 ${shown ? '' : 'opacity-0'}`} />
                  {col.label}
                </ContextMenuItem>
              );
            })}
            <ContextMenuItem onSelect={onResetColumns}>Reset to defaults</ContextMenuItem>
          </ContextMenuContent>
        </ContextMenu>

        <div className="relative" style={{ height: virtualizer.getTotalSize() }}>
          {virtualizer.getVirtualItems().map((row) => {
            const torrent = torrents[row.index];
            if (!torrent) return null;
            const isSelected = selection.has(torrent.id);
            const isFocused = focused === torrent.id;

            return (
              <ContextMenu key={torrent.id}>
                <ContextMenuTrigger asChild>
                  <div
                    onClick={(ev) => onRowClick(torrent, ev)}
                    onContextMenu={() => onRowContextMenu(torrent)}
                    style={{
                      position: 'absolute',
                      top: 0,
                      left: 0,
                      width: '100%',
                      height: row.size,
                      transform: `translateY(${row.start}px)`,
                      gridTemplateColumns: gridTemplate,
                    }}
                    className={`grid cursor-default items-center border-b border-border/40 text-xs ${
                      isSelected ? 'bg-primary/10' : 'hover:bg-muted/50'
                    } ${isFocused ? 'ring-1 ring-inset ring-primary/40' : ''}`}
                  >
                    {columns.map((col) => (
                      <div
                        key={col.key}
                        className={`min-w-0 overflow-hidden whitespace-nowrap px-2 ${
                          col.align === 'right'
                            ? 'text-right tabular-nums'
                            : col.align === 'center'
                              ? 'text-center'
                              : ''
                        }`}
                      >
                        {col.render(torrent)}
                      </div>
                    ))}
                  </div>
                </ContextMenuTrigger>
                <ContextMenuContent className="w-56">{rowMenu(torrent)}</ContextMenuContent>
              </ContextMenu>
            );
          })}
        </div>
      </div>
    </div>
  );
};
