/**
 * Grades Resolver - myGrades Query.
 *
 * 仲裁依据:
 *   - student-bff.schema.graphql Query.myGrades
 *   - coord-final-decisions §2 B4 (强制自我越权防御, 学生只能查自己成绩)
 *   - coord-final-decisions §2 B6 (Redis 5-30s 短缓存)
 */
import type { StudentBffContext } from "../../shared/graphql/yoga.js";
import { ok, fail } from "../../shared/action-state.js";
import { CacheTTL } from "../../shared/cache/cache.module.js";
import { UnauthorizedError } from "../../shared/errors/application-error.js";
import { assertOwnData } from "../guards/authorization.guard.js";

export const gradesResolvers = {
  Query: {
    /**
     * myGrades: 我的成绩列表.
     * @permission STUDENT_GRADE_READ
     * @dataScope OWN (B4 强制 studentId = userId)
     */
    async myGrades(
      _parent: unknown,
      args: {
        studentId?: string;
        subject?: string;
        page?: number;
        pageSize?: number;
      },
      ctx: StudentBffContext,
    ): Promise<unknown> {
      if (!ctx.userId) {
        throw new UnauthorizedError();
      }

      // B4 越权防御: args.studentId 必须 = JWT userId
      assertOwnData(ctx.userId, args.studentId);

      const page = args.page ?? 1;
      const pageSize = Math.min(args.pageSize ?? 20, 50);
      const cacheKey = `${ctx.userId}:${page}:${args.subject ?? "all"}`;

      const cached = await ctx.cache.get<unknown>("grades", cacheKey);
      if (cached) {
        return ok(cached, {
          traceId: ctx.traceId,
          cachedAt: new Date().toISOString(),
        });
      }

      try {
        const result = await ctx.downstream.call(
          "core-edu",
          "ListGradesByStudent",
          {
            studentId: ctx.userId,
            subject: args.subject,
            page,
            pageSize,
          },
          {
            traceId: ctx.traceId,
            metadata: { "x-user-id": ctx.userId },
          },
        );

        const data = result as { grades: unknown[]; totalCount: number };
        await ctx.cache.set("grades", data, CacheTTL.GRADES, cacheKey);
        return ok(data, { traceId: ctx.traceId });
      } catch (err) {
        return fail(
          "BFF_STUDENT_BAD_GATEWAY",
          `Failed to fetch grades: ${(err as Error).message}`,
          { i18nKey: "error.bffStudent.bad_gateway", traceId: ctx.traceId },
        );
      }
    },
  },
};
