// /readyz 探针注册表（president §2.4 + G2）
// DownstreamHealthCheck 注册表模式：每个下游注册独立探针，按阶段启用
// P2: Redis PING + iam gRPC 50052（2 项）
// P3+: + core-edu / content / data-ana / ai / msg（按阶段扩展）
//
// 软失败规则（contract §3.3）：
//   - 必需依赖（Redis / 已启用 gRPC 下游）失败返 503
//   - 可选依赖（未启用 gRPC 下游）失败仅告警返 200 + degraded: true

/** 单个健康检查结果 */
export interface HealthCheckResult {
  name: string;
  status: "up" | "down" | "degraded";
  latencyMs: number;
  required: boolean;
  error?: string;
}

/** /readyz 聚合结果 */
export interface ReadinessReport {
  status: "ok" | "degraded" | "unavailable";
  service: string;
  timestamp: string;
  checks: HealthCheckResult[];
  degraded?: boolean;
}

/** 健康检查探针接口（每个下游注册一个） */
export interface HealthProbe {
  /** 探针名称（如 "redis" / "iam-grpc"） */
  readonly name: string;
  /** 是否为必需依赖（必需失败返 503，可选失败返 200 + degraded） */
  readonly required: boolean;
  /** 执行健康检查 */
  check(): Promise<{
    status: "up" | "down";
    latencyMs: number;
    error?: string;
  }>;
}

/**
 * 健康检查注册表（DownstreamHealthCheck 模式）
 * 按阶段注册探针，/readyz 调用时遍历所有已注册探针
 */
export class HealthCheckRegistry {
  private readonly probes = new Map<string, HealthProbe>();

  register(probe: HealthProbe): void {
    this.probes.set(probe.name, probe);
  }

  unregister(name: string): void {
    this.probes.delete(name);
  }

  async runAll(): Promise<ReadinessReport> {
    const checks: HealthCheckResult[] = [];
    let hasRequiredDown = false;
    let hasOptionalDown = false;

    for (const probe of this.probes.values()) {
      try {
        const result = await probe.check();
        checks.push({
          name: probe.name,
          status: result.status,
          latencyMs: result.latencyMs,
          required: probe.required,
          error: result.error,
        });
        if (result.status === "down" && probe.required) {
          hasRequiredDown = true;
        } else if (result.status === "down" && !probe.required) {
          hasOptionalDown = true;
        }
      } catch (err) {
        checks.push({
          name: probe.name,
          status: "down",
          latencyMs: 0,
          required: probe.required,
          error: err instanceof Error ? err.message : String(err),
        });
        if (probe.required) {
          hasRequiredDown = true;
        } else {
          hasOptionalDown = true;
        }
      }
    }

    let status: ReadinessReport["status"];
    if (hasRequiredDown) {
      status = "unavailable";
    } else if (hasOptionalDown) {
      status = "degraded";
    } else {
      status = "ok";
    }

    return {
      status,
      service: "teacher-bff",
      timestamp: new Date().toISOString(),
      checks,
      degraded: hasOptionalDown && !hasRequiredDown,
    };
  }
}

/** 全局注册表实例（单例） */
export const healthRegistry = new HealthCheckRegistry();
