import { Controller, Get, HttpException, HttpStatus } from "@nestjs/common";
import { sql } from "drizzle-orm";
import { getDb } from "../../config/database.js";
import { esClient } from "../../config/elasticsearch.js";
import { getRedis } from "../redis/redis.client.js";
import { isKafkaHealthy } from "../kafka/kafka.client.js";
import { checkPushGateway } from "../push/push-gateway.client.js";

const SERVICE_NAME = "msg";

/**
 * 健康检查端点。
 *
 * 仲裁依据 G2：/readyz 多依赖检查（DB/ES/Redis/Kafka/PushGateway）。
 *
 * - GET /healthz：liveness，仅返回进程存活，不检查依赖。
 * - GET /readyz：readiness，检查 DB（关键）+ ES/Redis/Kafka/PushGateway（非关键）。
 *   DB 不可用返回 503；其他依赖降级标记但不影响 readyz 状态码。
 */

type CheckStatus = "ok" | "disabled" | "error";

interface DependencyCheck {
  status: CheckStatus;
  error?: string;
}

interface ReadyzResponse {
  status: "ok" | "degraded";
  service: string;
  timestamp: string;
  checks: {
    database: DependencyCheck;
    elasticsearch: DependencyCheck;
    redis: DependencyCheck;
    kafka: DependencyCheck;
    pushGateway: DependencyCheck;
  };
}

@Controller()
export class HealthController {
  @Get("healthz")
  liveness(): { status: string; service: string; timestamp: string } {
    return {
      status: "ok",
      service: SERVICE_NAME,
      timestamp: new Date().toISOString(),
    };
  }

  @Get("readyz")
  async readiness(): Promise<ReadyzResponse> {
    const checks: ReadyzResponse["checks"] = {
      database: { status: "ok" },
      elasticsearch: { status: "disabled" },
      redis: { status: "disabled" },
      kafka: { status: "ok" },
      pushGateway: { status: "disabled" },
    };

    // 1. DB（关键依赖）
    try {
      const db = getDb();
      await db.execute(sql`SELECT 1`);
    } catch (error) {
      checks.database = {
        status: "error",
        error: error instanceof Error ? error.message : "database unreachable",
      };
    }

    // 2. Elasticsearch（可选依赖）
    if (esClient) {
      try {
        await esClient.ping();
        checks.elasticsearch = { status: "ok" };
      } catch (error) {
        checks.elasticsearch = {
          status: "error",
          error: error instanceof Error ? error.message : "ES unreachable",
        };
      }
    }

    // 3. Redis（可选依赖）
    const redis = getRedis();
    if (redis) {
      try {
        const pong = await redis.ping();
        checks.redis = { status: pong === "PONG" ? "ok" : "error" };
      } catch (error) {
        checks.redis = {
          status: "error",
          error: error instanceof Error ? error.message : "Redis unreachable",
        };
      }
    }

    // 4. Kafka（非关键依赖，降级模式）
    checks.kafka = { status: isKafkaHealthy() ? "ok" : "error" };

    // 5. PushGateway（软失败，可选依赖）
    try {
      const pushOk = await checkPushGateway();
      checks.pushGateway = { status: pushOk ? "ok" : "error" };
    } catch {
      checks.pushGateway = {
        status: "error",
        error: "PushGateway unreachable",
      };
    }

    // DB 不可用 -> 503；其他依赖降级 -> 200 + degraded 标记
    const dbOk = checks.database.status === "ok";
    const allOk = dbOk && Object.values(checks).every((c) => c.status === "ok");

    if (!dbOk) {
      throw new HttpException(
        {
          status: "unavailable",
          service: SERVICE_NAME,
          timestamp: new Date().toISOString(),
          checks,
        },
        HttpStatus.SERVICE_UNAVAILABLE,
      );
    }

    return {
      status: allOk ? "ok" : "degraded",
      service: SERVICE_NAME,
      timestamp: new Date().toISOString(),
      checks,
    };
  }
}
