/**
 * MoveTargetDialog — 複数選択した項目の移動先フォルダを選ぶ軽量ダイアログ（Box 化 Phase 2）。
 * ドラッグ移動のキーボード/タッチ代替。フォルダだけを辿り、「ここに移動」で確定する。
 *
 * 実際の移動（move API 連打）と結果表示は呼出側（SpaceFiles）が onConfirm で行う。
 * ここは移動先 dir を決めることに専念し、no-op になる移動先では確定ボタンを無効化する。
 */
import { useCallback, useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { fetchSpaceFiles, type LocalFileEntry } from '../../api';
import { resolveMoves } from '../../lib/fileMove';
import { FileBreadcrumb } from './FileBreadcrumb';

interface MoveTargetDialogProps {
  spaceId: string;
  /** 移動する項目の相対パス集合。 */
  sourcePaths: string[];
  onClose: () => void;
  onConfirm: (destDir: string) => void;
  isMoving?: boolean;
}

export function MoveTargetDialog({ spaceId, sourcePaths, onClose, onConfirm, isMoving }: MoveTargetDialogProps) {
  const { t } = useTranslation('files');
  const [dir, setDir] = useState('');
  const [folders, setFolders] = useState<LocalFileEntry[]>([]);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState('');

  const load = useCallback(async (target: string) => {
    setLoading(true);
    setError('');
    try {
      const r = await fetchSpaceFiles(spaceId, target);
      setFolders(r.entries.filter(e => e.kind === 'directory'));
    } catch {
      setFolders([]);
      setError(t('move.loadFoldersError'));
    } finally {
      setLoading(false);
    }
  }, [spaceId, t]);

  useEffect(() => { void load(dir); }, [dir, load]);

  const { moves, skipped } = resolveMoves(sourcePaths, dir);
  const segments = dir ? dir.split('/').filter(Boolean) : [];

  return (
    <div
      className="fixed inset-0 z-50 flex items-center justify-center bg-black/40 p-4"
      onClick={onClose}
      role="presentation"
    >
      <div
        data-testid="move-target-dialog"
        role="dialog"
        aria-modal="true"
        aria-label={t('move.title', { count: sourcePaths.length })}
        className="w-full max-w-md rounded-lg border border-hairline bg-canvas shadow-xl"
        onClick={e => e.stopPropagation()}
      >
        <div className="flex items-center justify-between border-b border-hairline px-4 py-2.5">
          <h2 className="text-sm font-semibold text-slate-800">{t('move.title', { count: sourcePaths.length })}</h2>
          <button
            type="button"
            onClick={onClose}
            aria-label={t('move.close')}
            className="rounded p-1 text-slate-400 hover:bg-surface hover:text-slate-700"
          >
            <svg className="h-4 w-4" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.75" strokeLinecap="round">
              <path d="M4 4l8 8M12 4l-8 8" />
            </svg>
          </button>
        </div>

        <div className="px-4 py-3">
          <div className="mb-2">
            <FileBreadcrumb testid="move-target-breadcrumb" pathSegments={segments} onNavigate={setDir} />
          </div>

          <div className="max-h-64 overflow-y-auto rounded border border-hairline">
            {loading ? (
              <p className="px-3 py-6 text-center text-xs text-slate-400">{t('move.loading')}</p>
            ) : folders.length === 0 ? (
              <p className="px-3 py-6 text-center text-xs text-slate-400">
                {t('move.noSubfolders')}
              </p>
            ) : (
              <ul className="divide-y divide-hairline/60">
                {folders.map(f => (
                  <li key={f.path}>
                    <button
                      type="button"
                      data-testid={`move-target-folder-${f.name}`}
                      onClick={() => setDir(f.path)}
                      className="flex w-full items-center gap-2 px-3 py-2 text-left text-xs text-slate-700 hover:bg-surface"
                    >
                      <svg className="h-4 w-4 shrink-0 text-amber-400" viewBox="0 0 16 16" fill="currentColor">
                        <path d="M2 4.5A1.5 1.5 0 013.5 3h3l1.5 2h4.5A1.5 1.5 0 0114 6.5v5A1.5 1.5 0 0112.5 13h-9A1.5 1.5 0 012 11.5v-7z" />
                      </svg>
                      <span className="truncate">{f.name}</span>
                      <svg className="ml-auto h-3.5 w-3.5 shrink-0 text-slate-300" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
                        <path d="M6 4l4 4-4 4" />
                      </svg>
                    </button>
                  </li>
                ))}
              </ul>
            )}
          </div>

          {error && <p className="mt-2 text-xs text-red-600">{error}</p>}
          <p className="mt-2 text-2xs text-slate-500">
            {t('move.destination')} <span className="font-medium text-slate-700">{dir ? `/${dir}` : t('move.root')}</span>
            {skipped.length > 0 && <span className="text-slate-400">{t('move.skipped', { count: skipped.length })}</span>}
          </p>
        </div>

        <div className="flex items-center justify-end gap-2 border-t border-hairline px-4 py-2.5">
          <button
            type="button"
            onClick={onClose}
            className="inline-flex h-7 items-center rounded-md border border-hairline bg-canvas px-3 text-2xs font-medium text-slate-600 hover:bg-surface"
          >
            {t('move.cancel')}
          </button>
          <button
            type="button"
            data-testid="move-target-confirm"
            onClick={() => onConfirm(dir)}
            disabled={isMoving || moves.length === 0}
            className="inline-flex h-7 items-center rounded-md bg-[var(--brand-primary)] px-3 text-2xs font-semibold text-white hover:opacity-90 disabled:opacity-40"
          >
            {moves.length > 0 ? t('move.confirmCount', { count: moves.length }) : t('move.confirm')}
          </button>
        </div>
      </div>
    </div>
  );
}
