import { Injectable, OnModuleDestroy, OnModuleInit, Logger } from '@nestjs/common';
import { PrismaClient } from '@prisma/client';
import { tenantGuardExtension } from './tenant-guard.extension';

/**
 * 连接池随 cohort 并发自动放大 —— 免去手动给 DATABASE_URL 追加 `?connection_limit=`。
 *
 * 病根:并发旋钮是 PAC_COHORT_CONCURRENCY(N 个 cohort runner 共享一个池),
 * 但 Prisma 默认池大小是 `核数×2+1`,与 N 无关 → 一调并发就得手动调池。这里把两者联动:
 *   - 未设 / =1(常驻 API 进程)→ 不改 URL,走 Prisma 默认池;
 *   - >1(摄入是独立 process)→ connection_limit = N×6+5,封顶 40(守住 Postgres max_connections=100);
 *   - URL 里已显式写了 connection_limit → 尊重,不覆盖(逃生口)。
 * 摄入是独立进程,只有它拿大池,常驻服务仍是小池,天然隔离。
 */
function withCohortDerivedPool(rawUrl: string | undefined): string | undefined {
  if (!rawUrl) return rawUrl;
  let url: URL;
  try {
    url = new URL(rawUrl);
  } catch {
    return rawUrl; // 非标准 URL(如 unix socket)— 交给 Prisma 原样处理
  }
  if (url.searchParams.has('connection_limit')) return rawUrl;
  const n = Math.max(1, parseInt(process.env.PAC_COHORT_CONCURRENCY ?? '1', 10) || 1);
  if (n <= 1) return rawUrl;
  url.searchParams.set('connection_limit', String(Math.min(n * 6 + 5, 40)));
  return url.toString();
}

@Injectable()
export class PrismaService extends PrismaClient implements OnModuleInit, OnModuleDestroy {
  private readonly logger = new Logger(PrismaService.name);

  constructor() {
    super({
      datasourceUrl: withCohortDerivedPool(process.env.DATABASE_URL),
      log: [
        { level: 'warn', emit: 'event' },
        { level: 'error', emit: 'event' },
      ],
    });
    // 纵深防御:$extends 返回扩展客户端,从构造器 return 让 DI 拿到的就是它(透明,
    //   services 的 this.prisma.patient 不用改)。扩展按请求级 ALS 上下文自动注入 tenantId。
    //   $extends 不可变,故只能"构造器 return"这一处接入。
    return this.$extends(tenantGuardExtension) as unknown as PrismaService;
  }

  async onModuleInit(): Promise<void> {
    await this.$connect();
    this.logger.log('Prisma connected');
  }

  async onModuleDestroy(): Promise<void> {
    await this.$disconnect();
  }
}
