/**
 * E2E: the analyze `--embedding-dims` validation on the REAL CLI parse path.
 *
 * The fix for the dims crash lives in the commander `preAction` hook in
 * src/cli/index.ts, which must validate the value BEFORE the lazy
 * import('./analyze.js') triggers schema.ts's module-load read of
 * GITNEXUS_EMBEDDING_DIMS (which throws on a bad value). Direct
 * analyzeCommand() unit tests bypass the hook entirely, so this interaction —
 * commander hook timing + synchronous program.parse + lazy import + the
 * module-load throw — can only be exercised by running the actual binary.
 *
 * Reliability: every case here is INVALID dims, so the hook prints a friendly
 * error and process.exit(1)s *before* the action runs. No repo, no lazy
 * import, no pipeline, no DB, no network — just tsx startup + commander parse.
 * That makes these deterministic and fast, unlike the full-analyze e2e cases.
 *
 * Run via tsx (no build step), mirroring test/integration/cli-e2e.test.ts.
 */
import { spawnSync } from 'child_process';
import { createRequire } from 'module';
import os from 'os';
import path from 'path';
import fs from 'fs';
import { fileURLToPath, pathToFileURL } from 'url';

import { afterAll, beforeAll, describe, expect, it } from 'vitest';

const testDir = path.dirname(fileURLToPath(import.meta.url));
const repoRoot = path.resolve(testDir, '../..');
const cliEntry = path.join(repoRoot, 'src/cli/index.ts');

const _require = createRequire(import.meta.url);
const tsxPkgDir = path.dirname(_require.resolve('tsx/package.json'));
const tsxImportUrl = pathToFileURL(path.join(tsxPkgDir, 'dist', 'loader.mjs')).href;

let cwd: string;

beforeAll(() => {
  // The hook exits before any repo logic, so this dir need not be a git repo.
  cwd = fs.mkdtempSync(path.join(os.tmpdir(), 'gn-embed-dims-e2e-'));
});

afterAll(() => {
  fs.rmSync(cwd, { recursive: true, force: true });
});

function runAnalyze(args: string[]) {
  // Strip any ambient GITNEXUS_EMBEDDING_* so the flag is the sole input.
  const env = { ...process.env } as Record<string, string | undefined>;
  for (const k of Object.keys(env)) {
    if (k.startsWith('GITNEXUS_EMBEDDING_')) delete env[k];
  }
  // Pre-set the heap cap so analyzeCommand's ensureHeap() wouldn't re-exec
  // (would drop the tsx loader). Irrelevant on the invalid-dims path since the
  // hook exits first, but harmless and matches the cli-e2e harness.
  env.NODE_OPTIONS = `${process.env.NODE_OPTIONS || ''} --max-old-space-size=8192`.trim();
  return spawnSync(process.execPath, ['--import', tsxImportUrl, cliEntry, 'analyze', ...args], {
    cwd,
    encoding: 'utf8',
    timeout: 30_000,
    stdio: ['pipe', 'pipe', 'pipe'],
    env,
  });
}

describe('analyze --embedding-dims validation (real CLI parse path)', () => {
  it.each(['abc', '0', '-5', '1e3', '3.5'])(
    'rejects %j with a friendly error, not a raw module-load crash',
    (bad) => {
      const result = runAnalyze([cwd, '--embedding-dims', bad]);
      const stderr = result.stderr ?? '';

      // Non-zero exit (the hook called process.exit(1)).
      expect(result.status).toBe(1);

      // The friendly, flag-named message surfaced...
      expect(stderr).toContain('--embedding-dims must be a positive integer');

      // ...and NOT the raw schema.ts throw (env-var-named) that would appear if
      // the hook validation were removed and schema.ts crashed during the lazy
      // import. This is the regression guard for finding #1.
      expect(stderr).not.toContain('GITNEXUS_EMBEDDING_DIMS must be a positive integer');
      // No unhandled-rejection / stack-trace leakage either.
      expect(stderr).not.toContain('UnhandledPromiseRejection');
      expect(stderr).not.toMatch(/^\s+at .+:\d+:\d+/m);
    },
    30_000,
  );
});
