/**
 * 6.1: ExamHomeworkServicePort — 考试/作业模块的服务端口接口
 *
 * 目的：
 * - 为 app 层提供一个稳定的调用契约，屏蔽 modules 内部实现细节
 * - 便于单元测试时注入 mock 实现（无需真实 DB）
 * - 为未来可能的远程服务（BFF/API gateway）预留替换点
 *
 * 使用方式：
 *   import { EXAM_HOMEWORK_SERVICE_PROVIDER, type ExamHomeworkServicePort } from "@/shared/services/exam-homework-port"
 *   const service = EXAM_HOMEWORK_SERVICE_PROVIDER.get()
 *   const exam = await service.getExamById(id, scope)
 *
 * 实际实现位于 modules/exams/data-access.ts 与 modules/homework/data-access.ts，
 * 通过 registerExamHomeworkService() 在应用启动时注入。
 */

import type { DataScope } from "@/shared/types/permissions"
import type { Exam } from "@/modules/exams/types"
import type { HomeworkAssignmentListItem } from "@/modules/homework/types"
import type { ExamWithQuestionsForHomework } from "@/modules/exams/data-access"

/**
 * 考试/作业模块对外暴露的服务契约。
 * 仅包含 app 层和跨模块调用所需的方法，不暴露内部实现细节。
 */
export interface ExamHomeworkServicePort {
  // ===== 考试 =====
  /** 按 ID 获取考试（带数据范围过滤） */
  getExamById(id: string, scope?: DataScope): Promise<Exam | null>
  /** 获取考试列表 */
  getExams(params: {
    scope?: DataScope
    subjectId?: string
    gradeId?: string
    status?: string
    search?: string
  }): Promise<Exam[]>
  /** 获取考试创建者 ID（用于权限校验） */
  getExamCreatorId(examId: string): Promise<string | null>
  /** 获取考试标题（跨模块引用时使用，避免全量加载） */
  getExamTitleById(examId: string): Promise<string | null>

  // ===== 作业 =====
  /** 按 ID 获取作业 */
  getHomeworkAssignmentById(id: string, scope?: DataScope): Promise<HomeworkAssignmentListItem | null>
  /** 获取教师创建的作业列表 */
  getHomeworkAssignments(params: {
    creatorId?: string
    classId?: string
    scope?: DataScope
  }): Promise<HomeworkAssignmentListItem[]>
  /** 获取作业的最大分值（批量） */
  getAssignmentMaxScoreByIds(assignmentIds: string[]): Promise<Map<string, number>>

  // ===== 跨模块 =====
  /** 获取考试及其题目（供作业模块引用考试内容时使用） */
  getExamWithQuestionsForHomework(examId: string): Promise<ExamWithQuestionsForHomework | null>
}

/**
 * 服务提供者：单例注册 + 解析。
 *
 * - `register(impl)` 在应用启动时调用一次（如 instrumentation.ts）
 * - `get()` 在运行时获取当前实现
 * - 未注册时抛出明确错误，避免静默失败
 */
class ServiceProvider<T> {
  private impl: T | null = null

  register(impl: T): void {
    if (this.impl !== null) {
      // 允许重复注册（HMR 场景），覆盖旧实现
      if (process.env.NODE_ENV !== "production") {
        console.warn("[ServiceProvider] Re-registering service implementation (HMR?)")
      }
    }
    this.impl = impl
  }

  get(): T {
    if (this.impl === null) {
      throw new Error(
        "[ExamHomeworkServicePort] No implementation registered. " +
          "Call registerExamHomeworkService() during application startup."
      )
    }
    return this.impl
  }

  /** 测试专用：重置为未注册状态 */
  reset(): void {
    this.impl = null
  }
}

export const EXAM_HOMEWORK_SERVICE_PROVIDER = new ServiceProvider<ExamHomeworkServicePort>()

/**
 * 注册考试/作业服务实现。
 * 应在应用启动时调用（如 instrumentation.ts 或模块初始化）。
 */
export function registerExamHomeworkService(impl: ExamHomeworkServicePort): void {
  EXAM_HOMEWORK_SERVICE_PROVIDER.register(impl)
}
