/**
 * Cold Import CLI 入口
 *
 * Usage:
 *   pnpm cold-import -- --dir=./data/jvs-dw
 *   pnpm cold-import -- --dir=./data/jvs-dw --dry-run
 *
 * 通过 NestApplicationContext 启动(不起 HTTP),复用 DI:Prisma / ColdImportService。
 */

import { NestFactory } from '@nestjs/core';
import { Logger } from '@nestjs/common';
import { AppModule } from '../app.module';
import {
  ColdImportService,
  SyncAlreadyRunningError,
} from '../modules/sync/cold-import/cold-import.service';

interface CliArgs {
  dir?: string;
  dryRun: boolean;
  help: boolean;
  incremental: boolean;
  cohortBatchSize?: number | null; // null = 显式禁用分批,undefined = 用 env / 默认
}

function parseArgs(argv: string[]): CliArgs {
  const args: CliArgs = { dryRun: false, help: false, incremental: false };
  for (const a of argv) {
    if (a === '--help' || a === '-h') args.help = true;
    else if (a === '--dry-run') args.dryRun = true;
    else if (a === '--incremental') args.incremental = true;
    else if (a === '--no-cohort') args.cohortBatchSize = 0; // 显式禁用分批,跑 single-shot
    else if (a.startsWith('--cohort-batch=')) {
      const n = parseInt(a.slice('--cohort-batch='.length), 10);
      args.cohortBatchSize = Number.isFinite(n) && n >= 0 ? n : undefined;
    } else if (a.startsWith('--dir=')) args.dir = a.slice('--dir='.length);
  }
  return args;
}

function printHelp() {
  const lines = [
    '',
    'Cold Import CLI',
    '',
    '把宿主脱敏导出的目录(manifest.yaml + *.csv/*.json)装载到 PAC',
    '',
    'Usage:',
    '  pnpm cold-import -- --dir=<dir> [--dry-run]',
    '',
    'Options:',
    '  --dir=<path>          必填,manifest.yaml 所在目录(相对 / 绝对路径)',
    '  --dry-run             只读 + 翻译预览,不写库',
    '  --incremental         增量模式(读上次 cursor,SQL 注 WHERE > cursor;首跑等价全量)',
    '  --cohort-batch=<N>    按 patient 分批跑(default 5000;env PAC_COHORT_BATCH_SIZE 兜底)',
    '  --no-cohort           显式禁用分批,跑 single-shot(文件源或调试场景)',
    '  --help, -h            显示本帮助',
    '',
    'Examples:',
    '  pnpm cold-import -- --dir=./data/jvs-dw --dry-run',
    '  pnpm cold-import -- --dir=./data/jvs-dw',
    '  pnpm cold-import -- --dir=./data/jvs-dw --cohort-batch=2000',
    '  pnpm cold-import -- --dir=./data/jvs-dw --incremental',
    '',
  ];
  // eslint-disable-next-line no-console
  console.log(lines.join('\n'));
}

async function bootstrap() {
  const args = parseArgs(process.argv.slice(2));
  if (args.help || !args.dir) {
    printHelp();
    process.exit(args.help ? 0 : 1);
  }

  const logger = new Logger('cold-import:cli');
  logger.log(
    `Starting cold-import CLI(dir=${args.dir}, dryRun=${args.dryRun}, ` +
      `incremental=${args.incremental}, cohortBatch=${args.cohortBatchSize ?? '(default/env)'})`,
  );

  const app = await NestFactory.createApplicationContext(AppModule, {
    logger: ['log', 'warn', 'error'],
  });

  try {
    const svc = app.get(ColdImportService);
    const result = await svc.importDirectory(args.dir!, {
      dryRun: args.dryRun,
      incremental: args.incremental,
      cohortBatchSize: args.cohortBatchSize,
    });

    logger.log('─────────────────────────────────────────');
    logger.log(`Result:`);
    logger.log(`  runId:                 ${result.runId}`);
    logger.log(`  host:                  ${result.hostName} (${result.hostId})`);
    logger.log(`  tenants:               [${result.tenantIds.join(',')}]`);
    logger.log(`  dryRun:                ${result.dryRun}`);
    logger.log(`  status:                ${result.status}`);
    logger.log(`  syncLogId:             ${result.syncLogId ?? '(dryRun: no log)'}`);
    logger.log(`  patients upserted:     ${result.totals.patientsUpserted}`);
    logger.log(`  transactions written:  ${result.totals.transactionsWritten}`);
    logger.log(`  duplicates (idem):     ${result.totals.duplicates}`);
    logger.log(`  failed:                ${result.totals.failed}`);
    logger.log(
      `  facts:                 created=${result.totals.factsCreated} superseded=${result.totals.factsSuperseded} unchanged=${result.totals.factsUnchanged} evidence=${result.totals.factsEvidenceAppended} failed=${result.totals.factsFailed}`,
    );
    logger.log(`  per resource:`);
    for (const r of result.perResource) {
      logger.log(
        `    - ${r.resource}: fetched=${r.fetched} patients=${r.patientsUpserted} txns=${r.transactionsWritten} dups=${r.duplicates} failed=${r.failed} | facts(c=${r.factsCreated} s=${r.factsSuperseded} u=${r.factsUnchanged} e=${r.factsEvidenceAppended} f=${r.factsFailed})`,
      );
      if (args.dryRun && r.sampleCanonical.length > 0) {
        logger.log(`      sample canonical:`);
        for (const sample of r.sampleCanonical) {
          logger.log(`        ${JSON.stringify(sample)}`);
        }
      }
    }
    logger.log('─────────────────────────────────────────');
  } catch (err) {
    if (err instanceof SyncAlreadyRunningError) {
      logger.error(`并发拦截:已有其他 sync 在跑同 host:${err.message}`);
      logger.error('如果上次 sync 异常崩了未清理,手动 SQL 清:');
      logger.error(
        `  UPDATE sync_logs SET status='aborted', ended_at=NOW() ` +
          `WHERE host_id='<hostId>' AND status='running' AND started_at < NOW() - INTERVAL '12 hours';`,
      );
      process.exitCode = 4; // 4 = lock conflict(区分于 2 = 真失败 / 3 = bootstrap 崩)
    } else {
      logger.error('Cold import failed:');
      logger.error(err instanceof Error ? err.stack ?? err.message : String(err));
      process.exitCode = 2;
    }
  } finally {
    await app.close();
  }
}

bootstrap().catch((err) => {
  // eslint-disable-next-line no-console
  console.error(err);
  process.exit(3);
});
