import {
  downstreamCallsTotal,
  downstreamDurationSeconds,
  downstreamErrorsTotal,
} from "../../shared/observability/metrics.js";
import { callGrpc } from "./grpc.factory.js";
import { withCircuitBreaker } from "./circuit-breaker.js";

/**
 * 封装 gRPC 调用 + metrics 记录 + 熔断器（对齐 02-architecture-design.md §6.4 + §9）。
 *
 * 每次下游 gRPC 调用记录：
 * - downstream_calls_total { service, rpc, status }
 * - downstream_duration_seconds { service, rpc }
 * - downstream_errors_total { service, rpc, error_type }（仅失败时）
 *
 * P6.1：调用通过 withCircuitBreaker 包装，熔断开启时直接抛 503。
 */
export async function callWithMetrics<TReq, TRes>(
  client: unknown,
  method: string,
  request: TReq,
  serviceName: string,
): Promise<TRes> {
  return withCircuitBreaker(serviceName, async () => {
    const startedAt = Date.now();
    try {
      const result = await callGrpc<TReq, TRes>(
        client,
        method,
        request,
        serviceName,
      );
      const elapsed = (Date.now() - startedAt) / 1000;
      downstreamCallsTotal.inc({
        service: serviceName,
        rpc: method,
        status: "success",
      });
      downstreamDurationSeconds.observe(
        { service: serviceName, rpc: method },
        elapsed,
      );
      return result;
    } catch (err) {
      const elapsed = (Date.now() - startedAt) / 1000;
      const errorType = err instanceof Error ? err.constructor.name : "Unknown";
      downstreamCallsTotal.inc({
        service: serviceName,
        rpc: method,
        status: "error",
      });
      downstreamErrorsTotal.inc({
        service: serviceName,
        rpc: method,
        error_type: errorType,
      });
      downstreamDurationSeconds.observe(
        { service: serviceName, rpc: method },
        elapsed,
      );
      throw err;
    }
  });
}
