/**
 * Recompute Persona CLI
 *
 * 批量重算指定 host(默认 demo)所有 patient 的 Persona,产新版本。
 *
 * Usage:
 *   pnpm recompute-persona                   # 默认 host=demo,所有 active patient
 *   pnpm recompute-persona -- --host=friday  # 指定 host
 *   pnpm recompute-persona -- --pid=P001     # 单 patient(host 内 externalId)
 */
import { NestFactory } from '@nestjs/core';
import { Logger } from '@nestjs/common';
import { AppModule } from '../app.module';
import { PersonaService } from '../modules/persona/persona.service';
import { PrismaService } from '../prisma/prisma.service';

interface Args {
  host: string;
  pid?: string;
  pids?: string[]; // 多个 externalId(逗号分隔),定向重算受影响子集用
  force?: boolean; // 跳过水位幂等闸:算法/特征变更后(数据没变)也强制重算
}

function parseArgs(argv: string[]): Args {
  const args: Args = { host: 'demo' };
  for (const a of argv) {
    if (a.startsWith('--host=')) args.host = a.slice('--host='.length);
    else if (a.startsWith('--pid=')) args.pid = a.slice('--pid='.length);
    else if (a === '--force') args.force = true;
    else if (a.startsWith('--pids=')) {
      args.pids = a.slice('--pids='.length).split(',').map((s) => s.trim()).filter(Boolean);
    }
  }
  return args;
}

async function bootstrap() {
  const args = parseArgs(process.argv.slice(2));
  const logger = new Logger('recompute-persona');
  const app = await NestFactory.createApplicationContext(AppModule, {
    logger: ['log', 'warn', 'error'],
  });

  try {
    const prisma = app.get(PrismaService);
    const svc = app.get(PersonaService);

    const host = await prisma.host.findUnique({ where: { name: args.host } });
    if (!host) throw new Error(`Host '${args.host}' not found`);

    const patients = await prisma.patient.findMany({
      where: {
        hostId: host.id,
        active: true,
        ...(args.pids?.length ? { externalId: { in: args.pids } } : args.pid ? { externalId: args.pid } : {}),
      },
      select: { id: true, externalId: true, name: true },
    });

    logger.log(`Recomputing ${patients.length} patients for host=${args.host} ...`);

    // noop = 水位闸命中(自上次重算无新事件,沿用旧 persona),是正常结果,
    // 不能并入 failed —— 否则全量重跑(无新增事实)会误报"全失败"。
    let ok = 0, partial = 0, noop = 0, failed = 0;
    // 串行:persona 重算 Node-CPU-bound(特征计算占主),异步并发不提速(见 scheduler 注释)。
    for (const p of patients) {
      try {
        const r = await svc.recompute({
          patientId: p.id,
          source: `manual:cli`,
          force: args.force,
        });
        logger.log(
          `  ${p.externalId.padEnd(6)} ${(p.name ?? '').padEnd(12)} v${r.version} features=${r.featureCount} status=${r.status} (${r.durationMs}ms)`,
        );
        if (r.status === 'success') ok++;
        else if (r.status === 'partial') partial++;
        else if (r.status === 'noop') noop++;
        else failed++;
      } catch (err) {
        failed++;
        logger.error(`  ${p.externalId} FAILED: ${err instanceof Error ? err.message : err}`);
      }
    }

    logger.log('─────────────────────────────────');
    logger.log(`Done: success=${ok} partial=${partial} noop=${noop} failed=${failed}`);
  } catch (err) {
    new Logger('recompute-persona').error(err instanceof Error ? err.stack : String(err));
    process.exitCode = 2;
  } finally {
    await app.close();
  }
}

bootstrap().catch((err) => {
  console.error(err);
  process.exit(3);
});
