/*
- Date: 2026-06-29
  Spec: plans/2026-06-29-agent-backend-replay-orchestrator-spec.md
  Relationship: One-command local browser proof wrapper for the real backend
  replay path. It runs replay-agent-backend first, then points Playwright at the
  real frontend thread route and backend-produced summary artifact.
*/
import { spawn } from 'node:child_process';
import { existsSync } from 'node:fs';
import { mkdir } from 'node:fs/promises';
import { dirname, join, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';

const scriptDir = dirname(fileURLToPath(import.meta.url));
const packageRoot = resolve(scriptDir, '..');
const repoRoot = resolve(packageRoot, '..', '..');
const webRoot = join(repoRoot, 'kandan', 'server_v2', 'web');

type BrowserReplayOptions = {
  readonly backendArgs: readonly string[];
  readonly backendUrl: string;
  readonly outDir: string;
  readonly summaryPath: string;
  readonly browserAuthPath: string;
  readonly explicitBrowserAuthPath: boolean;
};

async function main(): Promise<void> {
  const args = stripLeadingSeparator(process.argv.slice(2));

  if (args.includes('--help')) {
    printHelp();
    return;
  }

  const options = parseArgs(args);
  await mkdir(options.outDir, { recursive: true });
  await runBackendReplay(options);
  await assertReplayArtifacts(options);
  await runBrowserProof(options);
}

function stripLeadingSeparator(args: readonly string[]): readonly string[] {
  return args[0] === '--' ? args.slice(1) : args;
}

function parseArgs(args: readonly string[]): BrowserReplayOptions {
  const backendUrl = argValue(args, '--backend-url');

  if (backendUrl === undefined) {
    throw new Error('provide --backend-url <url>');
  }

  if (args.includes('--dry-run')) {
    throw new Error(
      'browser proof requires a real backend replay; remove --dry-run'
    );
  }

  if (args.includes('--probe-backend')) {
    throw new Error(
      'browser proof requires a real backend replay; remove --probe-backend'
    );
  }

  const outDir = resolve(
    argValue(args, '--out-dir') ?? 'agent-backend-browser-replay-output'
  );
  const explicitBrowserAuth = argValue(args, '--browser-auth-file');
  const browserAuthPath = resolve(
    explicitBrowserAuth ?? join(outDir, 'browser-auth.json')
  );
  const backendArgs =
    explicitBrowserAuth === undefined
      ? [...args, '--browser-auth-file', browserAuthPath]
      : [...args];

  return {
    backendArgs,
    backendUrl,
    outDir,
    summaryPath: join(outDir, 'summary.json'),
    browserAuthPath,
    explicitBrowserAuthPath: explicitBrowserAuth !== undefined,
  };
}

async function runBackendReplay(options: BrowserReplayOptions): Promise<void> {
  await runCommand(
    'pnpm',
    [
      '--filter',
      '@linzumi/cli',
      'run',
      'replay:agent-backend',
      '--',
      ...options.backendArgs,
    ],
    repoRoot,
    process.env
  );
}

async function assertReplayArtifacts(
  options: BrowserReplayOptions
): Promise<void> {
  if (!existsSync(options.summaryPath)) {
    throw new Error(
      `backend replay did not write summary artifact: ${options.summaryPath}`
    );
  }

  if (!existsSync(options.browserAuthPath)) {
    const hint = options.explicitBrowserAuthPath
      ? 'check --browser-auth-file path'
      : 'the wrapper should have passed --browser-auth-file automatically';
    throw new Error(
      `backend replay did not write browser auth artifact: ${options.browserAuthPath}; ${hint}`
    );
  }
}

async function runBrowserProof(options: BrowserReplayOptions): Promise<void> {
  await runCommand(
    'bun',
    ['run', 'replay-harness:agent-backend-browser'],
    webRoot,
    {
      ...process.env,
      KANDAN_REPLAY_BASE_URL: options.backendUrl,
      KANDAN_AGENT_BACKEND_REPLAY_SUMMARY: options.summaryPath,
      KANDAN_AGENT_BACKEND_REPLAY_BROWSER_AUTH: options.browserAuthPath,
    }
  );
}

function runCommand(
  command: string,
  args: readonly string[],
  cwd: string,
  env: NodeJS.ProcessEnv
): Promise<void> {
  return new Promise((resolvePromise, reject) => {
    const child = spawn(command, args, {
      cwd,
      env,
      stdio: 'inherit',
    });

    child.on('error', reject);
    child.on('exit', (code, signal) => {
      if (code === 0) {
        resolvePromise();
        return;
      }

      reject(
        new Error(
          `${command} ${args.join(' ')} failed with ${
            signal === null
              ? `exit code ${code ?? 'unknown'}`
              : `signal ${signal}`
          }`
        )
      );
    });
  });
}

function argValue(args: readonly string[], name: string): string | undefined {
  const index = args.indexOf(name);

  if (index === -1) {
    return undefined;
  }

  const value = args[index + 1];

  if (value === undefined) {
    throw new Error(`${name} requires a value`);
  }

  return value;
}

function printHelp(): void {
  process.stdout.write(
    `Usage: pnpm --filter @linzumi/cli run replay:agent-backend-browser -- --fixture <path> --backend-url <url> [backend replay options]\n\nThis runs the real backend replay first, then runs the Kandan web replay harness\nPlaywright browser proof against the generated summary.json and browser auth\nartifact. It forwards backend replay options to replay:agent-backend.\n\nRequired:\n  --fixture <path>                  Agent replay fixture\n  --backend-url <url>               Running local Phoenix backend URL\n\nCommon options forwarded to replay:agent-backend:\n  --provider auto|codex|claude-code\n  --setup-fixture\n  --out-dir <path>                  Default: agent-backend-browser-replay-output\n  --speed immediate|realtime|<n>x|<n>ms\n  --require-feature <featureId>     Forwarded per-feature manifest/backend oracle gate
  --oracle-feature <featureId>      Candidate proof oracle without readiness gating\n  --browser-auth-file <path>        Optional; default: <out-dir>/browser-auth.json\n\nExample:\n  pnpm --filter @linzumi/cli run replay:agent-backend-browser -- \\\n    --fixture packages/linzumi-cli/test/fixtures/agent-raw-replay/real-probe/claude.ndjson \\\n    --provider claude-code \\\n    --backend-url http://127.0.0.1:4140 \\\n    --setup-fixture \\\n    --out-dir /tmp/agent-backend-replay-browser\n`
  );
}

main().catch((error) => {
  process.stderr.write(
    `${error instanceof Error ? (error.stack ?? error.message) : String(error)}\n`
  );
  process.exitCode = 1;
});
