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 { closeDb } from "./config/database.js";
import { closeNeo4j } from "./config/neo4j.js";
import { connectKafka, disconnectKafka } from "./config/kafka.js";
import { logger } from "./shared/observability/logger.js";
import { metricsRegistry } from "./shared/observability/metrics.js";
import { outboxPublisher } from "./shared/outbox/outbox.publisher.js";
import { neo4jSyncWorker } from "./shared/sync/neo4j-sync.worker.js";
import type { Request, Response } from "express";

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

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

  // 连接 Kafka producer（非阻塞——失败不阻止启动，Outbox 会重试）
  await connectKafka();

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

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

  // gRPC 微服务：端口 50054，加载 content.proto
  app.connectMicroservice<MicroserviceOptions>({
    transport: Transport.GRPC,
    options: {
      package: "next_edu_cloud.content.v1",
      protoPath: resolveProtoPath(),
      url: `0.0.0.0:${env.GRPC_PORT}`,
    },
  });

  // Prometheus 指标端点：不鉴权，供 Prometheus 抓取。
  app.getHttpAdapter().get("/metrics", async (_req: Request, res: Response) => {
    res.set("Content-Type", metricsRegistry.contentType);
    res.end(await metricsRegistry.metrics());
  });

  // 启动 HTTP + gRPC
  await app.startAllMicroservices();
  await app.listen(env.PORT);
  logger.info(
    { port: env.PORT, grpcPort: env.GRPC_PORT },
    "Content service started (HTTP + gRPC)",
  );

  // 启动 Outbox Publisher（轮询 pending 事件投递 Kafka）
  await outboxPublisher.start();

  // 启动 Neo4j Sync Worker（消费 Kafka 事件异步同步图谱）
  await neo4jSyncWorker.start();

  process.on("SIGTERM", async () => {
    logger.info("SIGTERM received, shutting down gracefully...");
    await neo4jSyncWorker.stop();
    await outboxPublisher.stop();
    await disconnectKafka();
    await app.close();
    await closeNeo4j();
    await closeDb();
    await shutdownTracer();
    process.exit(0);
  });

  process.on("SIGINT", async () => {
    logger.info("SIGINT received, shutting down gracefully...");
    await neo4jSyncWorker.stop();
    await outboxPublisher.stop();
    await disconnectKafka();
    await app.close();
    await closeNeo4j();
    await closeDb();
    await shutdownTracer();
    process.exit(0);
  });
}

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