import { afterEach, beforeEach, describe, expect, it } from 'vitest';
import { existsSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'fs';
import { tmpdir } from 'os';
import { join } from 'path';
import { seedWorkspaceAppTemplates } from './piece-runner.js';

// seedWorkspaceAppTemplates は orchestrator リポジトリの
// docs/examples/workspace-apps/ を、ジョブのワークスペース（jail 内）へ
// コピーする。エージェントのファイルツールは元の docs/ には到達できないため、
// この seed が「テンプレを土台にする」指示の前提になっている。
describe('seedWorkspaceAppTemplates', () => {
  let workspace: string;

  beforeEach(() => {
    workspace = mkdtempSync(join(tmpdir(), 'wsapp-seed-'));
  });

  afterEach(() => {
    rmSync(workspace, { recursive: true, force: true });
  });

  it('copies archetype templates into readonly/app-templates/', () => {
    seedWorkspaceAppTemplates(workspace);

    const noteEditor = join(workspace, 'readonly', 'app-templates', 'note-editor', 'index.html');
    expect(existsSync(noteEditor)).toBe(true);
  });

  it('seeds a template that embeds a working postMessage bridge (call helper)', () => {
    seedWorkspaceAppTemplates(workspace);

    const html = readFileSync(
      join(workspace, 'readonly', 'app-templates', 'note-editor', 'index.html'),
      'utf8',
    );
    // 正典ブリッジの要点: id 採番 + parent への postMessage + {ok,data,error} の突き合わせ。
    expect(html).toContain('window.parent.postMessage');
    expect(html).toContain('function call');
    expect(html).toMatch(/r\.ok\s*\?/);
  });

  it('places templates under readonly/ so they are protected from agent writes', () => {
    seedWorkspaceAppTemplates(workspace);
    expect(existsSync(join(workspace, 'readonly', 'app-templates'))).toBe(true);
  });

  it('is idempotent — a second seed over an existing one does not throw', () => {
    seedWorkspaceAppTemplates(workspace);
    expect(() => seedWorkspaceAppTemplates(workspace)).not.toThrow();
    expect(
      existsSync(join(workspace, 'readonly', 'app-templates', 'note-editor', 'index.html')),
    ).toBe(true);
  });

  it('is best-effort — never throws even if the workspace path is unusable', () => {
    // 既存ファイルをワークスペースとして渡すと mkdir/cp が失敗するが、
    // 関数内で握りつぶしてジョブを落とさない。
    const fileAsWorkspace = join(workspace, 'not-a-dir.txt');
    writeFileSync(fileAsWorkspace, 'x');
    expect(() => seedWorkspaceAppTemplates(fileAsWorkspace)).not.toThrow();
  });
});
