import { useTranslation } from 'react-i18next';
import { LocalFileEntry, getLocalFileRawUrl } from '../../api';
import { FileBreadcrumb } from './FileBreadcrumb';
import { FileTileGrid } from './FileTileGrid';
import { FileDetailList } from './FileDetailList';
import { FileActions, FileSelectionBar, FileDropzone, FileViewToggle, FileSortMenu, type FileSort } from './FileToolbar';
import { useFileView } from '../../hooks/useFileView';
import { workspaceDirRole } from '../../lib/workspaceDirs';

/**
 * タスク詳細のファイルタブで使う書込（アップロード/削除）操作一式。
 * `useFileBrowser` の戻り値から組み立てて渡す。undefined のときは読み取り専用
 * （共有ビュー等）で、ツールバー・選択・ドロップゾーンを出さない。
 */
export interface FileManagement {
  /** owner/admin か（UI でツールバーを出すか）。サーバ側でも再ゲートされる。 */
  canManage: boolean;
  /** 現在の区分がアップロード/削除可能か（input/output のみ true）。 */
  writableSection: boolean;
  selected: Set<string>;
  toggleSelect: (path: string) => void;
  toggleSelectAll: (paths: string[]) => void;
  upload: (files: File[]) => void;
  remove: (paths: string[]) => void;
  download: (paths: string[]) => void;
  isUploading: boolean;
  isDeleting: boolean;
  isDownloading: boolean;
  message: { text: string; kind: 'ok' | 'error' } | null;
}

interface FileBrowserProps {
  section: 'workspace' | 'input' | 'output' | 'logs';
  currentPath: string;
  entries: LocalFileEntry[];
  pathSegments: string[];
  taskId?: number;
  onSectionChange: (section: 'workspace' | 'input' | 'output' | 'logs') => void;
  onNavigate: (path: string) => void;
  onPreview: (path: string, name: string) => void;
  onRefresh?: () => void;
  isRefreshing?: boolean;
  management?: FileManagement;
  /**
   * ファイルのダウンロード/生 URL を組み立てる任意の上書き関数。
   * 指定すると本体既定の `getLocalFileRawUrl(taskId, section, path)` の代わりに使う。
   * 共有ビュー（`/api/shared/:token/files/raw`）のように taskId/section を持たない
   * 文脈で raw URL を差し替えるために足した後方互換 prop。未指定なら従来動作。
   */
  rawUrlFor?: (entry: LocalFileEntry) => string;
  /**
   * 区分タブ（workspace/input/output/logs）を隠すか。既定 false。
   * 共有ビューは output のみを配信するため true にして区分タブを出さない。
   */
  hideSections?: boolean;
}


export function FileBrowser({
  section,
  currentPath,
  entries,
  pathSegments,
  taskId,
  onSectionChange,
  onNavigate,
  onPreview,
  onRefresh,
  isRefreshing,
  management,
  rawUrlFor,
  hideSections,
}: FileBrowserProps) {
  const { t } = useTranslation('files');
  const SECTIONS = ['workspace', 'input', 'output', 'logs'] as const;
  const { viewMode, setViewMode, sort, setSort, toggleSort, sortedEntries } = useFileView(entries);
  // アイコン表示のドロップダウン（名前順/新しい順）は共有ソート状態の上に薄く乗せる。
  // サイズ順は詳細表示の列見出しから操作する。
  const menuSort: FileSort = sort.key === 'modified' ? 'newest' : 'name';
  const onMenuSort = (s: FileSort) =>
    setSort(s === 'newest' ? { key: 'modified', dir: 'desc' } : { key: 'name', dir: 'asc' });

  // 書込ツールバーを出す条件: management があり、owner/admin かつ書込可能区分。
  const canWrite = !!management && management.canManage && management.writableSection;
  // raw/ダウンロード URL ビルダー。明示の rawUrlFor を最優先し、
  // 無ければ taskId がある場合に限り本体既定（local raw URL）を使う。
  const fileHref = rawUrlFor ?? (taskId != null ? ((entry: LocalFileEntry) => getLocalFileRawUrl(taskId, section, entry.path)) : undefined);
  // 選択・一括削除/DL の対象: ファイル＋ユーザー作成フォルダ（構造フォルダ=workspaceDirRole 有
  // は足場なので除外）。フォルダ単体の zip DL は各行の onDownloadDir で扱う。
  const selectablePaths = sortedEntries
    .filter(e => e.kind !== 'directory' || !workspaceDirRole(e.path, e.name, e.kind))
    .map(e => e.path);
  const selectedInView = management ? selectablePaths.filter(p => management.selected.has(p)) : [];
  const allSelected = selectablePaths.length > 0 && selectedInView.length === selectablePaths.length;

  return (
    <div className="flex flex-col gap-3">
      {/* 区分タブ + アクション（追加 / 再読み込み） */}
      <div className="flex gap-1 flex-wrap items-center">
        {!hideSections && SECTIONS.map(s => (
          <button
            key={s}
            onClick={() => { onSectionChange(s); onNavigate(''); }}
            className={`px-2 h-7 rounded text-2xs font-medium border transition-colors ${
              section === s
                ? 'border-accent/60 bg-accent-soft text-accent font-semibold'
                : 'border-hairline bg-canvas text-slate-600 hover:bg-surface'
            }`}
          >
            {s}
          </button>
        ))}
        <div className="ml-auto">
          <FileActions
            idPrefix="task"
            canUpload={canWrite}
            onUploadFiles={files => management?.upload(files)}
            onRefresh={() => onRefresh?.()}
            isRefreshing={isRefreshing}
            isUploading={management?.isUploading}
          />
        </div>
      </div>

      {/* パンくず（現在地）+ 並び替え・表示切替。パスはパンくずのみで表す（テキスト二重表示を廃止）。 */}
      <div className="flex items-start justify-between gap-2">
        <div className="min-w-0 flex-1 pt-0.5">
          <FileBreadcrumb testid="task-files-breadcrumb" pathSegments={pathSegments} onNavigate={onNavigate} />
        </div>
        <div className="flex shrink-0 items-center gap-1.5">
          {viewMode === 'icon' && <FileSortMenu sort={menuSort} onChange={onMenuSort} />}
          <FileViewToggle idPrefix="task" mode={viewMode} onChange={setViewMode} />
        </div>
      </div>

      {/* step4「成果物の在りか」の案内。output 区分の最上位がまだ空のときだけ、
          エージェントの成果物がここに溜まることを控えめに示す（チャット空状態の
          案内と同じ文言・トーンに合わせる）。ファイルが出来たら自然に消える。 */}
      {section === 'output' && currentPath === '' && entries.length === 0 && (
        <p
          data-testid="output-empty-hint"
          className="rounded-md border border-hairline bg-surface px-3 py-2 text-2xs text-slate-400 leading-relaxed"
        >
          {t('browser.outputHint')}
        </p>
      )}

      {canWrite && selectablePaths.length > 0 && (
        <FileSelectionBar
          idPrefix="task"
          allSelected={allSelected}
          onToggleSelectAll={() => management?.toggleSelectAll(selectablePaths)}
          selectedCount={selectedInView.length}
          onDeleteSelected={() => management?.remove(selectedInView)}
          onDownloadSelected={() => management?.download(selectedInView)}
          isDeleting={management?.isDeleting}
          isDownloading={management?.isDownloading}
        />
      )}

      {management?.message && (
        <p className={`text-xs ${management.message.kind === 'ok' ? 'text-emerald-600' : 'text-red-600'}`}>
          {management.message.text}
        </p>
      )}

      <FileDropzone
        idPrefix="task"
        enabled={canWrite}
        isUploading={management?.isUploading}
        onDropFiles={files => management?.upload(files)}
      >
        {viewMode === 'detail' ? (
          <FileDetailList
            entries={sortedEntries}
            idPrefix="task"
            canManage={canWrite}
            selected={management?.selected ?? new Set()}
            onToggleSelect={path => management?.toggleSelect(path)}
            onOpenDir={onNavigate}
            onOpenFile={onPreview}
            onDeleteOne={path => management?.remove([path])}
            isDeleting={management?.isDeleting}
            fileHref={fileHref}
            onDownloadDir={management ? (path => management.download([path])) : undefined}
            sort={sort}
            onSort={toggleSort}
            emptyHint={canWrite
              ? t('browser.emptyManage')
              : t('empty')}
          />
        ) : (
          <FileTileGrid
            entries={sortedEntries}
            idPrefix="task"
            canManage={canWrite}
            selected={management?.selected ?? new Set()}
            onToggleSelect={path => management?.toggleSelect(path)}
            onOpenDir={onNavigate}
            onOpenFile={onPreview}
            onDeleteOne={path => management?.remove([path])}
            isDeleting={management?.isDeleting}
            fileHref={fileHref}
            onDownloadDir={management ? (path => management.download([path])) : undefined}
            emptyHint={canWrite
              ? t('browser.emptyManage')
              : t('empty')}
          />
        )}
      </FileDropzone>
    </div>
  );
}
