import { useCallback, useEffect, useRef, useState } from 'react';
import type { FileEntry } from '../schemas/file-entry.js';
import { useShadeFiles, type UseShadeFilesOptions } from './useShadeFiles.js';

export interface UseFileListResult {
  entries: FileEntry[];
  isLoading: boolean;
  error: unknown;
  hasMore: boolean;
  /** Reset and reload the first page. */
  refresh(): void;
  /** Append the next page (no-op when `hasMore === false`). */
  loadMore(): Promise<void>;
}

export interface UseFileListOptions extends UseShadeFilesOptions {
  pageSize?: number;
}

/**
 * Paginated list of `path` on `peer`. Fetches the first page on mount,
 * exposes `loadMore()` for subsequent pages.
 */
export function useFileList(
  peer: string,
  path: string,
  opts: UseFileListOptions = {},
): UseFileListResult {
  const filesOpts: UseShadeFilesOptions = {};
  if (opts.probeIntervalMs !== undefined) filesOpts.probeIntervalMs = opts.probeIntervalMs;
  const { fs } = useShadeFiles(peer, filesOpts);
  const pageSize = opts.pageSize ?? 100;
  const [entries, setEntries] = useState<FileEntry[]>([]);
  const [cursor, setCursor] = useState<string | undefined>(undefined);
  const [hasMore, setHasMore] = useState(false);
  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState<unknown>(null);
  const [tick, setTick] = useState(0);
  const inflightRef = useRef<AbortController | null>(null);

  // Initial load + reload on path/peer/refresh.
  useEffect(() => {
    if (fs === null) return;
    inflightRef.current?.abort();
    const ctrl = new AbortController();
    inflightRef.current = ctrl;
    setIsLoading(true);
    setError(null);
    fs.list(path, { pageSize, signal: ctrl.signal })
      .then((page) => {
        if (ctrl.signal.aborted) return;
        setEntries(page.entries);
        setHasMore(page.hasMore);
        setCursor(page.nextCursor);
      })
      .catch((err) => {
        if (!ctrl.signal.aborted) setError(err);
      })
      .finally(() => {
        if (!ctrl.signal.aborted) setIsLoading(false);
      });
    return () => {
      ctrl.abort();
    };
  }, [fs, path, pageSize, tick]);

  const loadMore = useCallback(async (): Promise<void> => {
    if (fs === null || !hasMore || cursor === undefined) return;
    setIsLoading(true);
    try {
      const page = await fs.list(path, { pageSize, cursor });
      setEntries((prev) => [...prev, ...page.entries]);
      setHasMore(page.hasMore);
      setCursor(page.nextCursor);
    } catch (err) {
      setError(err);
    } finally {
      setIsLoading(false);
    }
  }, [fs, path, pageSize, cursor, hasMore]);

  return {
    entries,
    isLoading,
    error,
    hasMore,
    refresh: () => setTick((t) => t + 1),
    loadMore,
  };
}
