// api.ts から分割（挙動不変）: スペースの永続ワークスペースファイル。
import { BASE, triggerBlobDownload } from './client';
import type { LocalFileEntry } from './task-files';

// --- Space files (永続ワークスペース {worktreeDir}/space/{id}/files) ---
// タスク版の files API（getLocalFileRawUrl 等）と同形だが、スペース id でキーする。

export async function fetchSpaceFiles(spaceId: string, path: string = ''): Promise<{ basePath: string; path: string; entries: LocalFileEntry[] }> {
  const params = new URLSearchParams();
  if (path) params.set('path', path);
  const qs = params.toString();
  const res = await fetch(`${BASE}/local/spaces/${spaceId}/files${qs ? `?${qs}` : ''}`);
  const data = await res.json();
  if (!res.ok) throw new Error(data?.error ?? 'Failed to list files');
  return data;
}

export async function fetchSpaceFileContent(spaceId: string, path: string): Promise<string> {
  const params = new URLSearchParams({ path });
  const res = await fetch(`${BASE}/local/spaces/${spaceId}/files/content?${params.toString()}`);
  if (!res.ok) {
    const data = await res.json().catch(() => ({}));
    throw new Error(data?.error ?? 'Failed to read file');
  }
  return await res.text();
}

export function getSpaceFileRawUrl(spaceId: string, path: string): string {
  const params = new URLSearchParams({ path });
  return `${BASE}/local/spaces/${spaceId}/files/raw?${params.toString()}`;
}

export function getSpaceTrustedHtmlUrl(spaceId: string, path: string): string {
  const params = new URLSearchParams({ path, trusted: '1' });
  return `${BASE}/local/spaces/${spaceId}/files/raw?${params.toString()}`;
}

export function getSpaceFileOfficePreviewUrl(spaceId: string, path: string): string {
  const params = new URLSearchParams({ path });
  return `${BASE}/local/spaces/${spaceId}/files/office-preview?${params.toString()}`;
}

export async function uploadSpaceFiles(
  spaceId: string,
  path: string,
  files: { name: string; contentBase64: string }[],
): Promise<{ uploaded: { name: string; path: string }[] }> {
  const res = await fetch(`${BASE}/local/spaces/${spaceId}/files/upload`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ path, files }),
  });
  const data = await res.json();
  if (!res.ok) throw new Error(data?.error ?? 'Failed to upload files');
  return data as { uploaded: { name: string; path: string }[] };
}

// スペースのワークスペースファイルを削除する。複数選択は paths（相対パス配列）で渡す。
// 各パスはサーバ側で spaceFilesDir に封じ込め（traversal は 400）、ファイルのみ対象。
// 存在しないパスは冪等にスキップされる。
export async function deleteSpaceFiles(
  spaceId: string,
  paths: string[],
): Promise<{ deleted: string[]; skipped: string[] }> {
  const res = await fetch(`${BASE}/local/spaces/${spaceId}/files/delete`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ paths }),
  });
  const data = await res.json();
  if (!res.ok) throw new Error(data?.error ?? 'Failed to delete files');
  return data as { deleted: string[]; skipped: string[] };
}

// スペースのワークスペースに空フォルダを作る（owner/editor のみ）。path は親からの
// 相対パス。サーバ側で spaceFilesDir に封じ込め（traversal は 400）。
export async function createSpaceFolder(
  spaceId: string,
  path: string,
): Promise<{ created: string }> {
  const res = await fetch(`${BASE}/local/spaces/${spaceId}/files/mkdir`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ path }),
  });
  const data = await res.json();
  if (!res.ok) throw new Error(data?.error ?? 'Failed to create folder');
  return data as { created: string };
}

// スペースのファイル/フォルダをリネーム・移動する（owner/editor のみ）。from→to は
// いずれも相対パス完全形。構造ディレクトリ（input/output/logs/apps/readonly）と隠しは
// 不可。衝突時はサーバが `{stem} (N){ext}` に自動リネームし、確定先 path を返す。
export async function moveSpaceFile(
  spaceId: string,
  from: string,
  to: string,
): Promise<{ from: string; to: string }> {
  const res = await fetch(`${BASE}/local/spaces/${spaceId}/files/move`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ from, to }),
  });
  const data = await res.json();
  if (!res.ok) throw new Error(data?.error ?? 'Failed to move');
  return data as { from: string; to: string };
}

// スペースの複数ファイルを zip でまとめてダウンロード（read）。サーバが paths を
// spaceFilesDir に封じ込め、ファイルのみ zip 化。1 件でも zip にする。
export async function downloadSpaceFilesZip(
  spaceId: string,
  paths: string[],
  filename = 'files.zip',
): Promise<void> {
  const res = await fetch(`${BASE}/local/spaces/${spaceId}/files/download-zip`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ paths }),
  });
  if (!res.ok) {
    const data = await res.json().catch(() => ({}));
    throw new Error(data?.error ?? 'Failed to download files');
  }
  triggerBlobDownload(await res.blob(), filename);
}

// スペースのワークスペースファイルを path 指定で 1 件書き込む（上書き許可）。
// content（UTF-8 テキスト）または contentBase64（任意バイナリ）のどちらかを渡す。
// サーバ側で canEditInSpace + ensurePathWithin によりゲートされる。ワークスペース・
// アプリの postMessage ブリッジ writeFile の代理に使う。
export async function writeSpaceFile(
  spaceId: string,
  path: string,
  body: { content: string } | { contentBase64: string },
): Promise<{ path: string; bytes: number }> {
  const res = await fetch(`${BASE}/local/spaces/${spaceId}/files/write`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ path, ...body }),
  });
  const data = await res.json();
  if (!res.ok) throw new Error(data?.error ?? 'Failed to write file');
  return data as { path: string; bytes: number };
}
