/**
 * student-bff 启动入口.
 *
 * 仲裁依据:
 *   - coord-final-decisions §1 G1 (Dockerfile 多阶段构建, EXPOSE 3009)
 *   - coord-final-decisions §1 G3 (/healthz liveness)
 *   - coord-final-decisions §1 G5 (/metrics 端点)
 *   - coord-final-decisions §1 G6 (OTel tracer)
 *   - coord-final-decisions §1 G8 (GlobalErrorFilter)
 *   - coord-final-decisions §1 G9 (优雅关闭 SIGTERM)
 *   - coord-final-decisions §2 B1 (GraphQL Yoga endpoint: POST /graphql)
 *   - port-allocation.md (HTTP 3009, 无 gRPC 对外)
 *
 * 启动流程:
 *   1. initTracer (OTel)
 *   2. NestFactory.create(AppModule)
 *   3. app.useGlobalFilters(GlobalErrorFilter)
 *   4. 挂载 GraphQL Yoga middleware (POST /graphql)
 *   5. 注册 /metrics 端点
 *   6. app.listen(3009)
 *   7. SIGTERM → app.close() → 关闭 Redis/gRPC/Tracer
 */
import "reflect-metadata";
import { NestFactory } from "@nestjs/core";
import type { NestExpressApplication } from "@nestjs/platform-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 { metricsRegistry } from "./shared/observability/metrics.js";
import { env } from "./config/env.js";
import { GRAPHQL_YOGA } from "./student/student.module.js";
import { REDIS_CLIENT } from "./shared/cache/cache.module.js";
import { DOWNSTREAM_CLIENT } from "./shared/downstream/downstream.module.js";
import { CircuitBreakerService } from "./shared/circuit-breaker/circuit-breaker.service.js";
import type { Redis } from "ioredis";
import type { DownstreamClient } from "@edu/shared-ts/bff";
import type { YogaServerInstance } from "graphql-yoga";
import type { Request, Response, NextFunction } from "express";

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

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

  // G8 全局错误过滤器
  app.useGlobalFilters(new GlobalErrorFilter());

  app.enableShutdownHooks();

  // B1 GraphQL Yoga endpoint 挂载
  const yoga = (await app.resolve(GRAPHQL_YOGA)) as YogaServerInstance<
    { req: Request; res: Response },
    Record<string, unknown>
  >;
  const httpAdapter = app.getHttpAdapter().getInstance();
  httpAdapter.use(
    "/graphql",
    (req: Request, res: Response, next: NextFunction) => {
      yoga.handle(req, res).catch((err: unknown) => {
        logger.error({ err }, "GraphQL Yoga handle error");
        next(err);
      });
    },
  );

  // G5 Prometheus 指标端点 (不鉴权)
  httpAdapter.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: "/graphql",
      playground: env.GRAPHQL_PLAYGROUND && env.NODE_ENV === "development",
      mockUpstream: env.MOCK_UPSTREAM,
      devMode: env.DEV_MODE,
    },
    "Student BFF started",
  );

  // G9 优雅关闭: SIGTERM → 关闭 HTTP → Redis → gRPC → Tracer
  process.on("SIGTERM", async () => {
    logger.info("SIGTERM received, shutting down gracefully");
    try {
      await app.close();

      const redis = app.get<Redis>(REDIS_CLIENT);
      await redis.quit();

      const downstream = app.get<DownstreamClient>(DOWNSTREAM_CLIENT);
      await downstream.close();

      const circuitBreaker = app.get<CircuitBreakerService>(
        CircuitBreakerService,
      );
      await circuitBreaker.shutdown();

      await shutdownTracer();
      logger.info("Graceful shutdown complete");
    } catch (err) {
      logger.error({ err }, "Error during graceful shutdown");
      process.exit(1);
    }
  });
}

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