/**
 * v2-P2-7: 带监控埋点的诊断服务工厂。
 *
 * 通过组合模式包装任意 DiagnosticService 实现，
 * 在关键操作前后调用 DiagnosticMonitor.track() 发送埋点事件。
 *
 * 设计要点：
 * - 不修改被包装的服务实现，仅添加监控层。
 * - 埋点失败不阻断业务流程（catch 后静默）。
 * - 记录操作耗时（durationMs）便于性能监控。
 * - 通过组合而非继承实现，符合"组合优先"原则。
 *
 * 用法：
 * ```tsx
 * const monitoredService = createMonitoredDiagnosticService(
 *   defaultDiagnosticService,
 *   noopDiagnosticMonitor,
 * )
 * ```
 */

import type { ActionState } from "@/shared/types/action-state"

import type {
  DiagnosticService,
  ExportResult,
  KnowledgePointStudent,
} from "./diagnostic-service"
import type {
  DiagnosticMonitor,
  DiagnosticEventName,
  DiagnosticEventProperties,
} from "./diagnostic-monitor"

/**
 * 包装 DiagnosticService，在每个操作前后发送监控事件。
 *
 * @param service 被包装的原始服务实现
 * @param monitor 监控实现（no-op 或真实埋点 SDK）
 */
export function createMonitoredDiagnosticService(
  service: DiagnosticService,
  monitor: DiagnosticMonitor,
): DiagnosticService {
  /**
   * 执行操作并追踪事件。
   * 埋点失败不阻断业务流程。
   */
  const withTracking = async <T>(
    eventName: DiagnosticEventName,
    properties: DiagnosticEventProperties,
    operation: () => Promise<ActionState<T>>,
  ): Promise<ActionState<T>> => {
    const start = Date.now()
    let result: ActionState<T>
    try {
      result = await operation()
    } catch (e) {
      // 埋点：记录失败
      try {
        await monitor.track(eventName, {
          ...properties,
          success: false,
          error: e instanceof Error ? e.message : String(e),
          durationMs: Date.now() - start,
        })
      } catch {
        // 埋点失败不阻断
      }
      throw e
    }
    // 埋点：记录成功或失败
    try {
      await monitor.track(eventName, {
        ...properties,
        success: result.success,
        error: result.success ? undefined : result.message,
        durationMs: Date.now() - start,
      })
    } catch {
      // 埋点失败不阻断
    }
    return result
  }

  return {
    async generateStudentReport(
      studentId: string,
      period: string,
    ): Promise<ActionState<string>> {
      return withTracking(
        "report_generated",
        { reportType: "individual", studentId, period },
        () => service.generateStudentReport(studentId, period),
      )
    },

    async generateClassReport(
      classId: string,
      period: string,
    ): Promise<ActionState<string>> {
      return withTracking(
        "report_generated",
        { reportType: "class", classId, period },
        () => service.generateClassReport(classId, period),
      )
    },

    async generateGradeReport(
      gradeId: string,
      period: string,
    ): Promise<ActionState<string>> {
      return withTracking(
        "report_generated",
        { reportType: "grade", gradeId, period },
        () => service.generateGradeReport(gradeId, period),
      )
    },

    async publishReport(id: string): Promise<ActionState<null>> {
      return withTracking(
        "report_published",
        { reportId: id },
        () => service.publishReport(id),
      )
    },

    async deleteReport(id: string): Promise<ActionState<null>> {
      return withTracking(
        "report_deleted",
        { reportId: id },
        () => service.deleteReport(id),
      )
    },

    async exportReport(reportId: string): Promise<ActionState<ExportResult>> {
      return withTracking(
        "report_exported",
        { reportId: reportId },
        () => service.exportReport(reportId),
      )
    },

    async getClassStudentsByKp(
      classId: string,
      knowledgePointId: string,
      threshold?: number,
    ): Promise<ActionState<KnowledgePointStudent[]>> {
      return withTracking(
        "class_kp_filtered",
        { classId, knowledgePointId, threshold },
        () => service.getClassStudentsByKp(classId, knowledgePointId, threshold),
      )
    },
  }
}
