/**
 * student-bff DataLoader 模块 - N+1 防御.
 *
 * 仲裁依据:
 *   - coord-final-decisions §2 B1 (GraphQL Yoga + DataLoader)
 *   - 004 §11.3 BFF 聚合模式图示
 *
 * DataLoader 用于:
 *   - Dashboard 内多学生场景批量加载作业/成绩 (避免 N+1 gRPC 调用)
 *   - 子字段解析时批量加载关联实体
 *
 * 实现策略:
 *   - 上游 proto 暂未支持批量 RPC (ListHomeworkByIds 等), DataLoader 内部
 *     使用 Promise.all 并行调用各 id 的 gRPC, 通过 batch + dedupe 减少 N+1.
 *   - 同一 tick 内相同 id 请求自动去重 (DataLoader 内置 cacheKeyFn).
 *   - 后续 coord 补全批量 RPC 后, 替换为真正的批量 gRPC 调用.
 */
import { Module, Scope } from "@nestjs/common";
import DataLoader from "dataloader";
import type { DownstreamClient } from "@edu/shared-ts/bff";

/**
 * 单个作业的 Loader 批量加载函数.
 *
 * 输入: homeworkId 列表
 * 输出: 作业详情列表 (与输入顺序一致, 失败项返回 null)
 */
export type HomeworkLoader = DataLoader<string, unknown, string>;

/**
 * 单个学生成绩的 Loader.
 */
export type GradesLoader = DataLoader<string, unknown, string>;

/**
 * 用户信息 Loader (Dashboard 内多用户场景).
 */
export type UserInfoLoader = DataLoader<string, unknown, string>;

/**
 * 创建 Homework DataLoader.
 *
 * 使用方式 (在 Resolver context 注入):
 *   const loader = createHomeworkLoader(downstream);
 *   const hw1 = await loader.load("h-001");
 *   const hw2 = await loader.load("h-002");
 *   // 单 tick 内并行调用 gRPC, 自动 dedupe
 */
export function createHomeworkLoader(downstream: DownstreamClient): HomeworkLoader {
  return new DataLoader<string, unknown, string>(async (homeworkIds) => {
    const results = await Promise.all(
      homeworkIds.map(async (id) => {
        try {
          return await downstream.call("core-edu", "GetHomework", { homeworkId: id });
        } catch {
          return null;
        }
      }),
    );
    return results;
  });
}

/**
 * 创建 Grades DataLoader.
 */
export function createGradesLoader(downstream: DownstreamClient): GradesLoader {
  return new DataLoader<string, unknown, string>(async (studentIds) => {
    const results = await Promise.all(
      studentIds.map(async (id) => {
        try {
          return await downstream.call("core-edu", "ListGradesByStudent", {
            studentId: id,
          });
        } catch {
          return null;
        }
      }),
    );
    return results;
  });
}

/**
 * 创建 UserInfo DataLoader.
 */
export function createUserInfoLoader(downstream: DownstreamClient): UserInfoLoader {
  return new DataLoader<string, unknown, string>(async (userIds) => {
    const results = await Promise.all(
      userIds.map(async (id) => {
        try {
          return await downstream.call("iam", "GetUserInfo", { userId: id });
        } catch {
          return null;
        }
      }),
    );
    return results;
  });
}

/**
 * DataLoader 工厂接口 (注入到 GraphQL context).
 */
export interface StudentBffDataLoaders {
  homework: HomeworkLoader;
  grades: GradesLoader;
  userInfo: UserInfoLoader;
}

/**
 * 创建全部 DataLoader (每个 GraphQL 请求一份).
 */
export function createDataLoaders(
  downstream: DownstreamClient,
): StudentBffDataLoaders {
  return {
    homework: createHomeworkLoader(downstream),
    grades: createGradesLoader(downstream),
    userInfo: createUserInfoLoader(downstream),
  };
}

/**
 * NestJS Module - 提供 DataLoader 工厂 (request scope).
 */
@Module({
  providers: [
    {
      provide: "DATA_LOADER_FACTORY",
      useFactory: (): typeof createDataLoaders => createDataLoaders,
      scope: Scope.TRANSIENT,
    },
  ],
  exports: ["DATA_LOADER_FACTORY"],
})
export class DataLoaderModule {}
