import { useRef, useCallback, useMemo, useState, useEffect } from 'react';
import { useVirtualizer } from '@tanstack/react-virtual';
import type { DirEntry, TaskSummary } from 'apps/FileBrowser';
import { FileItem } from './FileItem';

type ClipboardState = { paths: string[]; mode: 'copy' | 'cut' } | null;

type FileGridProps = {
  entries: DirEntry[];
  viewMode: 'grid' | 'list';
  currentPath: string;
  selected: Set<string>;
  clipboard: ClipboardState;
  onOpen: (entry: DirEntry) => void;
  onDelete: (entry: DirEntry) => void;
  onRename: (entry: DirEntry, newName: string) => void;
  onChat: (entry: DirEntry) => void;
  onSelect: (names: Set<string>) => void;
  onCut: () => void;
  onCopy: () => void;
  renamingName: string | null;
  onRenamingChange: (name: string | null) => void;
  getMatchingTasks: (fileName: string, entryType: 'file' | 'directory') => TaskSummary[];
  onRunTask: (task: TaskSummary, entry: DirEntry) => void;
  scrollRef: React.RefObject<HTMLDivElement | null>;
};

const LIST_ROW_HEIGHT = 42;
const GRID_ROW_HEIGHT = 130;
const GRID_GAP = 12;

const useColumnCount = (scrollRef: React.RefObject<HTMLDivElement | null>) => {
  const [cols, setCols] = useState(4);

  useEffect(() => {
    const el = scrollRef.current;
    if (!el) return;
    const measure = () => {
      const width = el.clientWidth - 32; // subtract p-4 (16px each side)
      // Breakpoints matching grid-cols-2 sm:3 md:4 lg:5 xl:6
      if (width >= 1280) setCols(6);
      else if (width >= 1024) setCols(5);
      else if (width >= 768) setCols(4);
      else if (width >= 640) setCols(3);
      else setCols(2);
    };
    measure();
    const observer = new ResizeObserver(measure);
    observer.observe(el);
    return () => observer.disconnect();
  }, [scrollRef]);

  return cols;
};

export const FileGrid = ({
  entries,
  viewMode,
  currentPath,
  selected,
  clipboard,
  onOpen,
  onDelete,
  onRename,
  onChat,
  onSelect,
  onCut,
  onCopy,
  renamingName,
  onRenamingChange,
  getMatchingTasks,
  onRunTask,
  scrollRef,
}: FileGridProps) => {
  const lastClickedIdx = useRef<number>(-1);

  const sorted = useMemo(
    () =>
      [...entries].sort((a, b) => {
        if (a.type !== b.type) return a.type === 'directory' ? -1 : 1;
        return a.name.localeCompare(b.name);
      }),
    [entries],
  );

  const handleSelect = useCallback(
    (entry: DirEntry, ev: React.MouseEvent) => {
      const idx = sorted.findIndex((e) => e.name === entry.name);

      if (ev.shiftKey && lastClickedIdx.current >= 0) {
        const start = Math.min(lastClickedIdx.current, idx);
        const end = Math.max(lastClickedIdx.current, idx);
        const next = new Set(selected);
        for (let i = start; i <= end; i++) {
          next.add(sorted[i]!.name);
        }
        onSelect(next);
      } else if (ev.ctrlKey || ev.metaKey) {
        const next = new Set(selected);
        if (next.has(entry.name)) {
          next.delete(entry.name);
        } else {
          next.add(entry.name);
        }
        onSelect(next);
        lastClickedIdx.current = idx;
      } else {
        onSelect(new Set([entry.name]));
        lastClickedIdx.current = idx;
      }
    },
    [sorted, selected, onSelect],
  );

  const cols = useColumnCount(scrollRef);
  const cutPaths = clipboard?.mode === 'cut' ? new Set(clipboard.paths) : new Set<string>();
  const anySelected = selected.size > 0;
  const entryPath = (name: string) => (currentPath === '/' ? `/${name}` : `${currentPath}/${name}`);

  const rowCount = viewMode === 'list' ? sorted.length : Math.ceil(sorted.length / cols);

  const virtualizer = useVirtualizer({
    count: rowCount,
    getScrollElement: () => scrollRef.current,
    estimateSize: () => (viewMode === 'list' ? LIST_ROW_HEIGHT : GRID_ROW_HEIGHT + GRID_GAP),
    overscan: 10,
  });

  if (entries.length === 0) {
    return <div className="flex items-center justify-center py-20 text-duck-dark/40 text-sm">This folder is empty</div>;
  }

  const renderItem = (entry: DirEntry) => (
    <FileItem
      key={entry.name}
      entry={entry}
      viewMode={viewMode}
      selected={selected.has(entry.name)}
      anySelected={anySelected}
      selectedCount={selected.size}
      isCut={cutPaths.has(entryPath(entry.name))}
      onOpen={onOpen}
      onDelete={onDelete}
      onRename={onRename}
      onChat={onChat}
      onSelect={handleSelect}
      onCut={onCut}
      onCopy={onCopy}
      forceRename={renamingName === entry.name}
      onRenamingChange={onRenamingChange}
      matchingTasks={getMatchingTasks(entry.name, entry.type)}
      onRunTask={onRunTask}
    />
  );

  return (
    <div className="file-grid relative w-full" style={{ height: virtualizer.getTotalSize() }}>
      {virtualizer.getVirtualItems().map((virtualRow) => {
        if (viewMode === 'list') {
          const entry = sorted[virtualRow.index]!;
          return (
            <div
              key={virtualRow.key}
              className="absolute left-0 w-full"
              style={{ top: virtualRow.start, height: virtualRow.size }}
            >
              {renderItem(entry)}
            </div>
          );
        }

        const startIdx = virtualRow.index * cols;
        const rowEntries = sorted.slice(startIdx, startIdx + cols);
        return (
          <div
            key={virtualRow.key}
            className="absolute left-0 w-full grid gap-3"
            style={{
              top: virtualRow.start,
              height: virtualRow.size - GRID_GAP,
              gridTemplateColumns: `repeat(${cols}, minmax(0, 1fr))`,
            }}
          >
            {rowEntries.map(renderItem)}
          </div>
        );
      })}
    </div>
  );
};
