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

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

type SortField = 'name' | 'size' | 'type' | 'date';
type SortDirection = 'asc' | 'desc';

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;
  onDownload: (entry: DirEntry) => void;
  onSelect: (names: Set<string>) => void;
  onCut: () => void;
  onCopy: () => void;
  renamingName: string | null;
  onRenamingChange: (name: string | null) => void;
  onReadAloud: (entry: DirEntry) => void;
  onOcr: (entry: DirEntry) => void;
  onTranscribe: (entry: DirEntry) => void;
  onExtractAudio: (entry: DirEntry) => void;
  onExtract: (entry: DirEntry) => void;
  getMatchingTasks: (fileName: string, entryType: 'file' | 'directory') => TaskSummary[];
  onRunTask: (task: TaskSummary, entry: DirEntry) => void;
  onCreateWorkspace: (entry: DirEntry) => void;
  scrollRef: React.RefObject<HTMLDivElement | null>;
};

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

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,
  onDownload,
  onSelect,
  onCut,
  onCopy,
  renamingName,
  onRenamingChange,
  onReadAloud,
  onOcr,
  onTranscribe,
  onExtractAudio,
  onExtract,
  getMatchingTasks,
  onRunTask,
  onCreateWorkspace,
  scrollRef,
}: FileGridProps) => {
  const lastClickedIdx = useRef<number>(-1);
  const [sortField, setSortField] = useState<SortField>('name');
  const [sortDirection, setSortDirection] = useState<SortDirection>('asc');

  const sorted = useMemo(() => {
    const compare = (a: DirEntry, b: DirEntry): number => {
      if (a.type !== b.type) return a.type === 'directory' ? -1 : 1;
      let result: number;
      switch (sortField) {
        case 'name':
          result = a.name.localeCompare(b.name);
          break;
        case 'size':
          result = a.size - b.size;
          break;
        case 'type': {
          const typeA = a.type === 'directory' ? 'directory' : getFileType(a.name);
          const typeB = b.type === 'directory' ? 'directory' : getFileType(b.name);
          result = typeA.localeCompare(typeB);
          if (result === 0) result = a.name.localeCompare(b.name);
          break;
        }
        case 'date':
          result = a.modifiedAt - b.modifiedAt;
          break;
      }
      return sortDirection === 'asc' ? result : -result;
    };
    return [...entries].sort(compare);
  }, [entries, sortField, sortDirection]);

  const toggleSort = (field: SortField) => {
    if (sortField === field) {
      setSortDirection((d) => (d === 'asc' ? 'desc' : 'asc'));
    } else {
      setSortField(field);
      setSortDirection('asc');
    }
  };

  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,
    scrollMargin: HEADER_HEIGHT,
  });

  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}
      onDownload={onDownload}
      onSelect={handleSelect}
      onCut={onCut}
      onCopy={onCopy}
      forceRename={renamingName === entry.name}
      onRenamingChange={onRenamingChange}
      onReadAloud={onReadAloud}
      onOcr={onOcr}
      onTranscribe={onTranscribe}
      onExtractAudio={onExtractAudio}
      onExtract={onExtract}
      matchingTasks={getMatchingTasks(entry.name, entry.type)}
      onRunTask={onRunTask}
      onCreateWorkspace={onCreateWorkspace}
    />
  );

  const sortIcon = (field: SortField) =>
    sortField === field ? (
      sortDirection === 'asc' ? (
        <ChevronUp className="h-3 w-3" />
      ) : (
        <ChevronDown className="h-3 w-3" />
      )
    ) : null;

  const sortBtnClass = (field: SortField) =>
    `flex items-center gap-1 text-xs font-medium cursor-pointer transition-colors ${
      sortField === field ? 'text-duck-teal' : 'text-duck-dark/50 hover:text-duck-dark/80'
    }`;

  return (
    <>
      {viewMode === 'list' ? (
        <div
          className="sticky top-0 z-10 bg-background/95 backdrop-blur-sm border-b border-duck-dark/10 flex items-center gap-3 px-3"
          style={{ height: HEADER_HEIGHT }}
        >
          <span className="shrink-0 w-5" />
          <span className="shrink-0 w-5" />
          <button className={`flex-1 min-w-0 ${sortBtnClass('name')}`} onClick={() => toggleSort('name')}>
            Name {sortIcon('name')}
          </button>
          <button
            className={`hidden md:flex shrink-0 w-20 justify-end ${sortBtnClass('type')}`}
            onClick={() => toggleSort('type')}
          >
            Type {sortIcon('type')}
          </button>
          <button
            className={`hidden md:flex shrink-0 w-20 justify-end ${sortBtnClass('size')}`}
            onClick={() => toggleSort('size')}
          >
            Size {sortIcon('size')}
          </button>
          <button
            className={`hidden md:flex shrink-0 w-28 justify-end ${sortBtnClass('date')}`}
            onClick={() => toggleSort('date')}
          >
            Date {sortIcon('date')}
          </button>
          <span className="shrink-0 w-8" />
        </div>
      ) : (
        <div
          className="sticky top-0 z-10 bg-background/95 backdrop-blur-sm border-b border-duck-dark/10 flex items-center gap-2 px-3"
          style={{ height: HEADER_HEIGHT }}
        >
          <span className="text-xs text-duck-dark/40">Sort:</span>
          {(['name', 'size', 'type', 'date'] as SortField[]).map((field) => (
            <button
              key={field}
              onClick={() => toggleSort(field)}
              className={`flex items-center gap-1 px-2 py-1 rounded-md text-xs cursor-pointer transition-colors ${
                sortField === field
                  ? 'bg-duck-teal/10 text-duck-teal font-medium'
                  : 'text-duck-dark/50 hover:bg-duck-dark/5'
              }`}
            >
              {field.charAt(0).toUpperCase() + field.slice(1)}
              {sortIcon(field)}
            </button>
          ))}
        </div>
      )}
      <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>
    </>
  );
};
