/**
 * harness-gateway.ts — AppFileGateway implementation for the headless test harness (Task 5).
 *
 * Mirrors createSpaceGateway exactly in endpoint shapes, but:
 *  - Every fetch carries the token via __appToken query param AND x-app-token header.
 *  - rawUrl also carries __appToken so that img src / asset rewriting works without
 *    a separate header-based auth (browsers follow img src without custom headers).
 *  - Both writeFile and deleteFile are defined (gateway is not read-only).
 *
 * This lets the app-harness headless page drive the REAL AppRunner component against
 * real space files, authenticated via the short-lived harness token minted by Task 4.
 */

import type { AppFileGateway } from '../components/spaces/app-file-gateway';

/** Base API path — same origin, no trailing slash. */
const BASE = '/api/local';

/**
 * Build a URL to the space-files API, appending the token so the
 * app-harness auth middleware can verify the request without a session cookie.
 */
function spaceUrl(spaceId: string, suffix: string, params: Record<string, string>, token: string): string {
  const qs = new URLSearchParams({ ...params, __appToken: token });
  return `${BASE}/spaces/${spaceId}/files${suffix}?${qs.toString()}`;
}

/** Shared request headers: always include x-app-token for the middleware. */
function authHeaders(token: string): Record<string, string> {
  return { 'x-app-token': token };
}

/**
 * Create a token-authenticated AppFileGateway for use in the headless harness.
 *
 * @param spaceId  The space whose files this gateway accesses.
 * @param token    Short-lived JWT minted by the token-mint endpoint (Task 4).
 */
export function createHarnessGateway(spaceId: string, token: string): AppFileGateway {
  return {
    /** Read a file as text. Mirrors fetchSpaceFileContent endpoint shape. */
    async fetchContent(path: string): Promise<string> {
      const url = spaceUrl(spaceId, '/content', { path }, token);
      const res = await fetch(url, { headers: authHeaders(token) });
      if (!res.ok) {
        const data = await res.json().catch(() => ({}));
        throw new Error((data as any)?.error ?? 'HarnessGateway: Failed to read file');
      }
      return res.text();
    },

    /** List files in a directory. Mirrors fetchSpaceFiles endpoint shape. */
    async listFiles(dir: string): Promise<{ entries: import('../api').LocalFileEntry[] }> {
      const params: Record<string, string> = {};
      if (dir) params.path = dir;
      const url = spaceUrl(spaceId, '', params, token);
      const res = await fetch(url, { headers: authHeaders(token) });
      if (!res.ok) {
        const data = await res.json().catch(() => ({}));
        throw new Error((data as any)?.error ?? 'HarnessGateway: Failed to list files');
      }
      return res.json();
    },

    /**
     * Raw asset URL — used by rewriteRelativeAssets / img src.
     * Must carry __appToken because browsers follow img src without custom headers.
     */
    rawUrl(path: string): string {
      return spaceUrl(spaceId, '/raw', { path }, token);
    },

    /** Write a file. Mirrors writeSpaceFile endpoint shape (POST /files/write). */
    async writeFile(path: string, content: string): Promise<{ ok: boolean }> {
      const url = spaceUrl(spaceId, '/write', {}, token);
      const res = await fetch(url, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json', ...authHeaders(token) },
        body: JSON.stringify({ path, content }),
      });
      const data = await res.json();
      if (!res.ok) throw new Error((data as any)?.error ?? 'HarnessGateway: Failed to write file');
      return { ok: true };
    },

    /** Delete a file. Mirrors deleteSpaceFiles endpoint shape (POST /files/delete). */
    async deleteFile(path: string): Promise<{ ok: boolean }> {
      const url = spaceUrl(spaceId, '/delete', {}, token);
      const res = await fetch(url, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json', ...authHeaders(token) },
        body: JSON.stringify({ paths: [path] }),
      });
      const data = await res.json();
      if (!res.ok) throw new Error((data as any)?.error ?? 'HarnessGateway: Failed to delete file');
      return { ok: true };
    },
  };
}
