import "reflect-metadata";
import { NestFactory } from "@nestjs/core";
import { Transport, MicroserviceOptions } from "@nestjs/microservices";
import { join } from "node:path";
import { existsSync } from "node:fs";
import { AppModule } from "./app.module.js";
import { GlobalErrorFilter } from "./shared/errors/global-error.filter.js";
import { initTracer, shutdownTracer } from "./shared/observability/tracer.js";
import { env } from "./config/env.js";
import { logger } from "./shared/observability/logger.js";
import { metricsRegistry } from "./shared/observability/metrics.js";
import { getJwtKeyPair } from "./config/jwt.js";
import type { Request, Response } from "express";

/**
 * 解析 proto 文件路径。
 * 开发环境：从 monorepo 根目录的 packages/shared-proto/proto/ 加载
 *   - 当 cwd 为 monorepo 根（如 CI）→ packages/shared-proto/proto/iam.proto
 *   - 当 cwd 为 services/iam（pnpm --filter run dev）→ ../../packages/shared-proto/proto/iam.proto
 * 生产环境（Docker）：从服务本地的 ./proto/ 加载（Dockerfile COPY）
 */
function resolveProtoPath(): string {
  const monorepoRootPath = join(
    process.cwd(),
    "packages",
    "shared-proto",
    "proto",
    "iam.proto",
  );
  const monorepoParentPath = join(
    process.cwd(),
    "..",
    "..",
    "packages",
    "shared-proto",
    "proto",
    "iam.proto",
  );
  const localPath = join(process.cwd(), "proto", "iam.proto");
  if (existsSync(monorepoRootPath)) return monorepoRootPath;
  if (existsSync(monorepoParentPath)) return monorepoParentPath;
  if (existsSync(localPath)) return localPath;
  return monorepoParentPath;
}

/**
 * IAM 服务启动入口。
 *
 * 双入口（president §2.16）：
 * - HTTP server：env.PORT（3002），供 gateway 透传 + admin-portal 直连
 * - gRPC server：env.GRPC_PORT（50052），供 BFF 聚合调用（I1 裁决）
 *
 * 启动顺序：
 * 1. initTracer（OTel SDK）
 * 2. 创建 NestApplication
 * 3. 注册 GlobalErrorFilter
 * 4. 启动 gRPC microservice（hybrid app）
 * 5. 启动 HTTP server
 * 6. 预加载 JWT 密钥对（确保文件可读）
 */
async function bootstrap(): Promise<void> {
  initTracer();

  // 预加载 JWT 密钥对（启动时即校验文件可读，避免运行时才发现配置错误）
  getJwtKeyPair();

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

  app.useGlobalFilters(new GlobalErrorFilter());
  app.enableShutdownHooks();

  // gRPC microservice（端口 50052，I1 裁决）
  app.connectMicroservice<MicroserviceOptions>({
    transport: Transport.GRPC,
    options: {
      package: "next_edu_cloud.iam.v1",
      protoPath: resolveProtoPath(),
      url: `0.0.0.0:${env.GRPC_PORT}`,
    },
  });

  // Prometheus 指标端点
  app.getHttpAdapter().get("/metrics", async (_req: Request, res: Response) => {
    res.set("Content-Type", metricsRegistry.contentType);
    res.end(await metricsRegistry.metrics());
  });

  // 启动 hybrid app（HTTP + gRPC）
  await app.startAllMicroservices();
  await app.listen(env.PORT);

  logger.info(
    { httpPort: env.PORT, grpcPort: env.GRPC_PORT },
    "IAM service started (HTTP + gRPC dual entry)",
  );

  process.on("SIGTERM", async () => {
    await app.close();
    await shutdownTracer();
  });
}

bootstrap().catch((err: unknown) => {
  logger.error({ err }, "Failed to start IAM service");
  process.exit(1);
});
