/**
 * create-ba-order CLI — Entry point.
 *
 * Receives the user-validated module dependency graph, builds a topological
 * sort into parallel BA waves, and writes ba-order.md + ba-order.json.
 *
 * Usage:
 *   npx tsx skills/business-analyse/create-ba-order/cli/create-ba-order/index.ts \
 *     --spec '{"baRoot": ".smartstack/ba", "apps": ["CRM"], "modules": [...]}'
 */
import { parseArgs } from 'node:util';
import path from 'node:path';
import { generateEnvelope, failGenerate, printEnvelope } from '../../../../lib/output.js';
import { ensureDirectory, writeText, writeJson } from '../../../../lib/fs.js';
import { validate } from './validate.js';
import { buildBaOrderPlan } from './graph.js';
import { generateBaOrder } from './generate.js';
import type { ModuleDep, ModuleKey } from './types.js';
import { moduleKey } from './types.js';

const COMMAND = 'create-ba-order';

async function main(): Promise<void> {
  // --- 1. Parse CLI arguments ---
  const { values } = parseArgs({
    options: {
      spec: { type: 'string' },
    },
    strict: false,
  });

  if (!values.spec) {
    printEnvelope(failGenerate(COMMAND, ['Missing required --spec argument']));
    process.exit(1);
  }

  let raw: unknown;
  try {
    raw = JSON.parse(values.spec);
  } catch {
    printEnvelope(failGenerate(COMMAND, ['Invalid JSON in --spec argument']));
    process.exit(1);
  }

  // --- 2. Validate ---
  const validation = await validate(raw);
  if (!validation.valid || !validation.spec) {
    printEnvelope(failGenerate(COMMAND, validation.errors));
    process.exit(1);
  }

  const spec = validation.spec;
  const allWarnings = [...validation.warnings];

  // --- 3. Build internal module structures ---
  const modules: ModuleDep[] = spec.modules.map((m) => ({
    appCode: m.appCode,
    moduleCode: m.moduleCode,
    key: moduleKey(m.appCode, m.moduleCode),
    dependsOn: m.dependsOn as ModuleKey[],
  }));

  // --- 4. Build dependency graph + topological sort ---
  const plan = buildBaOrderPlan(modules, spec.apps);
  allWarnings.push(...plan.warnings);

  // --- 5. Generate markdown ---
  const outputDir = path.join(spec.baRoot, '_plan');
  const mdPath = path.join(outputDir, 'ba-order.md');
  const file = generateBaOrder(plan, mdPath);

  // --- 6. Write files (markdown + JSON) ---
  await ensureDirectory(outputDir);
  await writeText(file.path, file.content);

  const jsonPath = path.join(outputDir, 'ba-order.json');
  await writeJson(jsonPath, plan);

  // --- 7. Print envelope ---
  const baWaves = plan.waves.filter((w) => w.level > 0);
  const externalCount = plan.waves.find((w) => w.level === 0)?.modules.length ?? 0;

  printEnvelope(
    generateEnvelope(COMMAND, {
      data: {
        appCount: spec.apps.length,
        moduleCount: plan.totalModules,
        waveCount: baWaves.length,
        cycleCount: plan.cycles.length,
        externalDepCount: externalCount,
      },
      filesCreated: [path.resolve(file.path), path.resolve(jsonPath)],
      warnings: allWarnings,
      nextSteps: [
        `Review the BA order: ${mdPath}`,
        'Start BA phases (actors → screens) for Wave 1 modules first',
        'Proceed wave by wave — each wave depends on the previous one',
      ],
    }),
  );
}

main().catch((err) => {
  printEnvelope(
    failGenerate(COMMAND, [err instanceof Error ? err.message : String(err)]),
  );
  process.exit(1);
});
