// teacher-bff 入口（B1 裁决：P2 起 GraphQL Yoga）
// 优雅关闭顺序（G9）：HTTP → Redis → gRPC → Tracer
import "reflect-metadata";
import { NestFactory } from "@nestjs/core";
import type { NestExpressApplication } from "@nestjs/platform-express";
import type { Application, Request, Response } from "express";
import { AppModule } from "./app.module.js";
import { GlobalErrorFilter } from "./shared/errors/global-error.filter.js";
import { initTracer, shutdownTracer } from "./shared/observability/tracer.js";
import { logger } from "./shared/observability/logger.js";
import { env } from "./config/env.js";
import { metricsRegistry } from "./shared/observability/metrics.js";
import { closeAllGrpcClients } from "./clients/grpc/grpc.factory.js";

async function bootstrap(): Promise<void> {
  initTracer();

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

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

  // Prometheus 指标端点：不鉴权，供 Prometheus 抓取
  // 直接获取 Express 实例注册路由，避免 HttpAdapter 泛型类型不兼容
  const expressApp = app.getHttpAdapter().getInstance() as Application;
  expressApp.get("/metrics", async (_req: Request, res: Response) => {
    res.set("Content-Type", metricsRegistry.contentType);
    res.end(await metricsRegistry.metrics());
  });

  await app.listen(env.PORT);
  logger.info(
    {
      port: env.PORT,
      graphql: env.GRAPHQL_PATH,
      devMode: env.TEACHER_BFF_DEV_MODE,
      iamTarget: env.IAM_GRPC_TARGET,
    },
    "Teacher BFF started (GraphQL + gRPC downstream)",
  );

  // 优雅关闭（G9：HTTP → Redis → gRPC → Tracer）
  const shutdown = async (signal: string) => {
    logger.info({ signal }, "Shutting down Teacher BFF");
    try {
      await app.close(); // 触发 OnModuleDestroy（Redis quit）
      closeAllGrpcClients(); // 关闭所有 gRPC channel
      await shutdownTracer();
      logger.info("Teacher BFF shutdown complete");
    } catch (err) {
      logger.error({ err }, "Error during shutdown");
      process.exit(1);
    }
  };

  process.on("SIGTERM", () => void shutdown("SIGTERM"));
  process.on("SIGINT", () => void shutdown("SIGINT"));
}

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