import { useState, useEffect, useCallback, useRef } from 'react';
import {
  fetchLocalFiles,
  uploadLocalFiles,
  deleteLocalFiles,
  downloadLocalFilesZip,
  type LocalFileEntry,
  type WritableTaskSection,
} from '../api';
import { filesToBase64 } from '../lib/fileBase64';

type FileSection = 'workspace' | 'input' | 'output' | 'logs';

/** アップロード・削除が許される区分（サーバの WRITABLE_SECTIONS と一致）。 */
function isWritableSection(section: FileSection): section is WritableTaskSection {
  return section === 'input' || section === 'output';
}

export function useFileBrowser(taskId: number | null) {
  // 初期値は reset effect（task 切替で 'output' に倒す）と一致させる。'workspace' 初期だと
  // 初回 fetch が古い section で走り、reset 後の fetch とレースになる。
  const [section, setSection] = useState<FileSection>('output');
  const [currentPath, setCurrentPath] = useState('');
  const [entries, setEntries] = useState<LocalFileEntry[]>([]);
  const [isRefreshing, setIsRefreshing] = useState(false);
  // fetch のリクエスト連番。古い (taskId/section/path) のレスポンスが後勝ちで entries を
  // 上書きするのを防ぐため、最新の seq の結果だけ反映する。
  const reqSeq = useRef(0);
  // 複数選択（チェック済みファイルの相対パス集合）と書込中フラグ・メッセージ。
  const [selected, setSelected] = useState<Set<string>>(() => new Set());
  const [isUploading, setIsUploading] = useState(false);
  const [isDeleting, setIsDeleting] = useState(false);
  const [isDownloading, setIsDownloading] = useState(false);
  const [message, setMessage] = useState<{ text: string; kind: 'ok' | 'error' } | null>(null);

  // Fetch entries when taskId/section/path changes
  useEffect(() => {
    if (!taskId) return;
    const seq = ++reqSeq.current;
    fetchLocalFiles(taskId, section, currentPath)
      .then(r => { if (seq === reqSeq.current) setEntries(r.entries); })
      .catch(() => { if (seq === reqSeq.current) setEntries([]); });
  }, [taskId, section, currentPath]);

  // Reset when task changes
  useEffect(() => {
    setSection('output');
    setCurrentPath('');
  }, [taskId]);

  // フォルダ移動・区分切替・タスク切替で選択をクリア（別ディレクトリのパスを持ち越さない）。
  useEffect(() => { setSelected(new Set()); }, [taskId, section, currentPath]);

  const refresh = useCallback(async () => {
    if (!taskId) return;
    const seq = ++reqSeq.current;
    setIsRefreshing(true);
    try {
      const r = await fetchLocalFiles(taskId, section, currentPath);
      if (seq === reqSeq.current) setEntries(r.entries);
    } catch {
      if (seq === reqSeq.current) setEntries([]);
    } finally {
      setIsRefreshing(false);
    }
  }, [taskId, section, currentPath]);

  const toggleSelect = useCallback((path: string) => {
    setSelected(prev => {
      const next = new Set(prev);
      if (next.has(path)) next.delete(path); else next.add(path);
      return next;
    });
  }, []);

  const toggleSelectAll = useCallback((paths: string[]) => {
    setSelected(prev => {
      const allSelected = paths.length > 0 && paths.every(p => prev.has(p));
      return allSelected ? new Set() : new Set(paths);
    });
  }, []);

  const upload = useCallback(async (fileList: File[]) => {
    if (!taskId || fileList.length === 0 || !isWritableSection(section)) return;
    setIsUploading(true);
    setMessage(null);
    try {
      const payload = await filesToBase64(fileList);
      const r = await uploadLocalFiles(taskId, section, currentPath, payload);
      await refresh();
      setMessage({ text: `${r.uploaded.length} 件のファイルを追加しました`, kind: 'ok' });
    } catch (e) {
      setMessage({ text: `アップロードに失敗しました: ${(e as Error)?.message ?? ''}`, kind: 'error' });
    } finally {
      setIsUploading(false);
    }
  }, [taskId, section, currentPath, refresh]);

  const remove = useCallback(async (paths: string[]) => {
    if (!taskId || paths.length === 0 || !isWritableSection(section)) return;
    if (!window.confirm(`${paths.length} 件を削除しますか？フォルダはその中身ごと削除されます。この操作は取り消せません。`)) return;
    setIsDeleting(true);
    setMessage(null);
    try {
      const r = await deleteLocalFiles(taskId, section, paths);
      setSelected(new Set());
      await refresh();
      setMessage({ text: `${r.deleted.length} 件のファイルを削除しました`, kind: 'ok' });
    } catch (e) {
      setMessage({ text: `削除に失敗しました: ${(e as Error)?.message ?? ''}`, kind: 'error' });
    } finally {
      setIsDeleting(false);
    }
  }, [taskId, section, currentPath, refresh]);

  // 選択ファイルを zip でダウンロード（read 操作、全 section 可）。
  const download = useCallback(async (paths: string[]) => {
    if (!taskId || paths.length === 0) return;
    setIsDownloading(true);
    setMessage(null);
    try {
      await downloadLocalFilesZip(taskId, section, paths);
    } catch (e) {
      setMessage({ text: `ダウンロードに失敗しました: ${(e as Error)?.message ?? ''}`, kind: 'error' });
    } finally {
      setIsDownloading(false);
    }
  }, [taskId, section]);

  const pathSegments = currentPath ? currentPath.split('/').filter(Boolean) : [];

  return {
    section, setSection,
    currentPath, setCurrentPath,
    entries,
    isRefreshing,
    refresh,
    pathSegments,
    // 書込（アップロード/削除）
    writableSection: isWritableSection(section),
    selected, toggleSelect, toggleSelectAll,
    upload, remove, download,
    isUploading, isDeleting, isDownloading,
    message,
  };
}
