import { spawnSync } from 'node:child_process';
import { fileURLToPath } from 'node:url';
import { describe, expect, it } from 'vitest';
import { Command } from 'commander';
import { registerBrainCommand } from '@mosaicstack/brain';
import { registerForgeCommand } from '@mosaicstack/forge';
import { registerLogCommand } from '@mosaicstack/log';
import { registerMacpCommand } from '@mosaicstack/macp';
import { registerMemoryCommand } from '@mosaicstack/memory';
import { registerQueueCommand } from '@mosaicstack/queue';
import { registerStorageCommand } from '@mosaicstack/storage';
import { registerAuthCommand } from './commands/auth.js';
import { registerConfigCommand } from './commands/config.js';

// CU-05-10 — integration smoke test
// Asserts every sub-package CLI registered via register<Name>Command() attaches
// a top-level command to the root program and that its help output renders
// without throwing. This is the "mosaic <cmd> --help exits 0" gate that
// guards the sub-package CLI surface (CU-05-01..08) from silent breakage.

const CLI_PATH = fileURLToPath(new URL('../dist/cli.js', import.meta.url));

const REGISTRARS: Array<[string, (program: Command) => void]> = [
  ['auth', registerAuthCommand],
  ['brain', registerBrainCommand],
  ['config', registerConfigCommand],
  ['forge', registerForgeCommand],
  ['log', registerLogCommand],
  ['macp', registerMacpCommand],
  ['memory', registerMemoryCommand],
  ['queue', registerQueueCommand],
  ['storage', registerStorageCommand],
];

describe('sub-package CLI smoke (CU-05-10)', () => {
  for (const [name, register] of REGISTRARS) {
    it(`registers the "${name}" command on the root program`, () => {
      const program = new Command();
      register(program);
      const cmd = program.commands.find((c) => c.name() === name);
      expect(cmd, `expected top-level "${name}" command`).toBeDefined();
    });

    it(`"${name}" help output renders without throwing`, () => {
      const program = new Command().exitOverride();
      register(program);
      const cmd = program.commands.find((c) => c.name() === name);
      expect(cmd).toBeDefined();
      expect(() => cmd!.helpInformation()).not.toThrow();
    });
  }

  it.each(['source', 'decisions', 'observations'] as const)(
    'production CLI emits one blocked JSON object for bare --%s',
    (bareOption) => {
      const args = [
        CLI_PATH,
        'fleet',
        'migrate-v1',
        'preview',
        '--source=source',
        '--decisions=decisions',
        '--observations=observations',
      ];
      args[args.findIndex((argument) => argument.startsWith(`--${bareOption}=`))] =
        `--${bareOption}`;

      const result = spawnSync(process.execPath, args, { encoding: 'utf8' });
      const outputLines = result.stdout.trim().split('\n');

      expect(result.status).toBe(1);
      expect(result.stderr).toBe('');
      expect(outputLines).toHaveLength(1);
      expect(JSON.parse(outputLines[0]!)).toEqual({
        status: 'blocked',
        blockers: [
          {
            code: 'missing-migration-preview-option-value',
            path: `request.${bareOption}`,
            detail: 'Required migration preview option value is missing.',
          },
        ],
      });
    },
  );

  it('all nine sub-package commands coexist on a single program', () => {
    const program = new Command();
    for (const [, register] of REGISTRARS) register(program);
    const names = program.commands.map((c) => c.name()).sort();
    expect(names).toEqual([
      'auth',
      'brain',
      'config',
      'forge',
      'log',
      'macp',
      'memory',
      'queue',
      'storage',
    ]);
  });
});
