/**
 * PushGatewayService - push-gateway 推送通道封装.
 *
 * 仲裁依据:
 *   - workline §5.5 (P5.5 push-gateway 推送通道)
 *   - president-final-rulings §2.4 (软失败: 推送失败不阻塞主流程)
 *
 * 职责:
 *   1. 封装 push-gateway HTTP 调用 (POST /push/user/:userId)
 *   2. 超时控制 (3s AbortSignal.timeout)
 *   3. 指标记录 (student_bff_event_pushed_total)
 *   4. 软失败处理 (失败仅 warn 日志, 不抛异常)
 *
 * 消费方:
 *   - EventSubscriberService: Kafka 事件消费后推送
 *   - 未来可直接由 resolver 调用 (如主动推送通知)
 */
import { Injectable } from "@nestjs/common";
import promClient from "prom-client";
import { env } from "../../config/env.js";
import { logger } from "../../shared/observability/logger.js";
import { metricsRegistry } from "../../shared/observability/metrics.js";

/**
 * 推送消息结构.
 */
export interface PushMessage {
  type: string;
  topic: string;
  payload: unknown;
  timestamp: string;
}

/**
 * push-gateway 推送结果.
 */
export interface PushResult {
  success: boolean;
  status: number;
  error?: string;
}

@Injectable()
export class PushGatewayService {
  /**
   * 推送消息给指定学生.
   *
   * 调用 push-gateway POST /push/user/:userId,
   * 失败软处理 (president §2.4), 不抛异常.
   *
   * @param studentId 学生 ID
   * @param topic Kafka topic 名
   * @param eventType 事件类型
   * @param payload 事件载荷
   * @param timestamp 事件时间戳
   * @returns PushResult 推送结果
   */
  async pushToStudent(
    studentId: string,
    topic: string,
    eventType: string,
    payload: unknown,
    timestamp: string,
  ): Promise<PushResult> {
    const message: PushMessage = {
      type: eventType,
      topic,
      payload,
      timestamp,
    };

    try {
      const response = await fetch(
        `${env.PUSH_GATEWAY_URL}/push/user/${studentId}`,
        {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify(message),
          signal: AbortSignal.timeout(3000),
        },
      );

      const pushStatus = response.ok ? "success" : `http_${response.status}`;
      (
        metricsRegistry.getSingleMetric("student_bff_event_pushed_total") as
          promClient.Counter<string> | undefined
      )?.inc({ topic, push_status: pushStatus });

      if (!response.ok) {
        logger.warn(
          { studentId, topic, status: response.status },
          "Push-gateway returned non-OK status",
        );
      }

      return { success: response.ok, status: response.status };
    } catch (err) {
      logger.warn(
        { err, studentId, topic },
        "Push-gateway push failed (soft failure)",
      );
      (
        metricsRegistry.getSingleMetric("student_bff_event_pushed_total") as
          promClient.Counter<string> | undefined
      )?.inc({ topic, push_status: "error" });

      return {
        success: false,
        status: 0,
        error: (err as Error).message,
      };
    }
  }
}
