/**
 * student-bff prom-client metrics.
 *
 * 仲裁依据: coord-final-decisions §1 G5 (首次实现即 /metrics + 基础业务指标)
 *           02-architecture-design.md §6.4 (11 个 student_bff_* 指标)
 *
 * 指标命名: <service>_<module>_<operation>_<unit> (project_rules §12)
 */
import promClient from "prom-client";

const registry = new promClient.Registry();
registry.setDefaultLabels({ service: "student-bff" });

// 1. 请求总数
registry.registerMetric(
  new promClient.Counter({
    name: "student_bff_requests_total",
    help: "Total number of student-bff HTTP/GraphQL requests",
    labelNames: ["operation", "method", "status"],
  }),
);

// 2. 请求延迟
registry.registerMetric(
  new promClient.Histogram({
    name: "student_bff_request_duration_seconds",
    help: "Student-bff request duration in seconds",
    labelNames: ["operation", "method"],
    buckets: [0.01, 0.05, 0.1, 0.3, 0.5, 1, 3, 5],
  }),
);

// 3. 下游调用总数
registry.registerMetric(
  new promClient.Counter({
    name: "student_bff_downstream_calls_total",
    help: "Total downstream gRPC calls",
    labelNames: ["service", "method", "status"],
  }),
);

// 4. 下游调用延迟
registry.registerMetric(
  new promClient.Histogram({
    name: "student_bff_downstream_duration_seconds",
    help: "Downstream gRPC call duration in seconds",
    labelNames: ["service", "method"],
    buckets: [0.01, 0.05, 0.1, 0.3, 0.5, 1, 3, 5],
  }),
);

// 5. 下游错误数
registry.registerMetric(
  new promClient.Counter({
    name: "student_bff_downstream_errors_total",
    help: "Downstream gRPC call errors",
    labelNames: ["service", "method", "error_type"],
  }),
);

// 6. 缓存命中
registry.registerMetric(
  new promClient.Counter({
    name: "student_bff_cache_hits_total",
    help: "Cache hit count",
    labelNames: ["cache_key_pattern"],
  }),
);

// 7. 缓存未命中
registry.registerMetric(
  new promClient.Counter({
    name: "student_bff_cache_misses_total",
    help: "Cache miss count",
    labelNames: ["cache_key_pattern"],
  }),
);

// 8. 熔断器状态 (P6)
registry.registerMetric(
  new promClient.Gauge({
    name: "student_bff_circuit_state",
    help: "Circuit breaker state (0=closed, 1=open, 2=half-open)",
    labelNames: ["service", "state"],
  }),
);

// 9. SSE 连接数 (P5)
registry.registerMetric(
  new promClient.Gauge({
    name: "student_bff_sse_connections",
    help: "Active SSE connections",
  }),
);

// 10. 事件消费数 (P5)
registry.registerMetric(
  new promClient.Counter({
    name: "student_bff_event_consumed_total",
    help: "Kafka events consumed",
    labelNames: ["topic", "event_type"],
  }),
);

// 11. 推送数 (P5)
registry.registerMetric(
  new promClient.Counter({
    name: "student_bff_event_pushed_total",
    help: "Push-gateway push count",
    labelNames: ["topic", "push_status"],
  }),
);

// 自动收集 Node.js 进程级指标
promClient.collectDefaultMetrics({ register: registry });

export { registry as metricsRegistry };

/**
 * 下游调用指标辅助器 (供 DownstreamClient 调用).
 */
export function recordDownstreamCall(
  service: string,
  method: string,
  status: "success" | "error",
  durationMs: number,
  errorType?: string,
): void {
  const labels = { service, method, status };
  (
    registry.getSingleMetric("student_bff_downstream_calls_total") as
      promClient.Counter<string> | undefined
  )?.inc(labels);
  (
    registry.getSingleMetric("student_bff_downstream_duration_seconds") as
      promClient.Histogram<string> | undefined
  )?.observe({ service, method }, durationMs / 1000);
  if (status === "error" && errorType) {
    (
      registry.getSingleMetric("student_bff_downstream_errors_total") as
        promClient.Counter<string> | undefined
    )?.inc({ service, method, error_type: errorType });
  }
}

/**
 * 缓存命中/未命中指标辅助器.
 */
export function recordCacheAccess(keyPattern: string, hit: boolean): void {
  if (hit) {
    (
      registry.getSingleMetric("student_bff_cache_hits_total") as
        promClient.Counter<string> | undefined
    )?.inc({ cache_key_pattern: keyPattern });
  } else {
    (
      registry.getSingleMetric("student_bff_cache_misses_total") as
        promClient.Counter<string> | undefined
    )?.inc({ cache_key_pattern: keyPattern });
  }
}
