/**
 * Analytics Resolver - myWeakness / myTrend Queries (P4 扩展).
 *
 * 仲裁依据:
 *   - student-bff.schema.graphql Query.myWeakness / myTrend / studentDashboard
 *   - coord-final-decisions §2 B2 (gRPC 调用 data-ana)
 *   - coord-final-decisions §2 B4 (强制自我越权防御, 学情诊断仅本人可查)
 *   - coord-final-decisions §2 B6 (Redis 5-30s 短缓存)
 *   - president-final-rulings §2.3 (跨阶段扩展例外)
 */
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 analyticsResolvers = {
  Query: {
    /**
     * myWeakness: 学情诊断 (薄弱知识点).
     * @permission STUDENT_ANALYTICS_READ
     * @dataScope OWN
     */
    async myWeakness(
      _parent: unknown,
      args: { studentId?: string },
      ctx: StudentBffContext,
    ): Promise<unknown> {
      if (!ctx.userId) {
        throw new UnauthorizedError();
      }

      assertOwnData(ctx.userId, args.studentId);

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

      try {
        const result = await ctx.downstream.call(
          "data-ana",
          "GetStudentWeakness",
          {
            studentId: ctx.userId,
          },
          {
            traceId: ctx.traceId,
            metadata: { "x-user-id": ctx.userId },
          },
        );

        await ctx.cache.set(
          "analytics:weakness",
          result,
          CacheTTL.ANALYTICS_WEAKNESS,
          ctx.userId,
        );
        return ok(result, { traceId: ctx.traceId });
      } catch (err) {
        return fail(
          "BFF_STUDENT_BAD_GATEWAY",
          `Failed to fetch weakness: ${(err as Error).message}`,
          { i18nKey: "error.bffStudent.bad_gateway", traceId: ctx.traceId },
        );
      }
    },

    /**
     * myTrend: 学习趋势.
     * @permission STUDENT_ANALYTICS_READ
     * @dataScope OWN
     */
    async myTrend(
      _parent: unknown,
      args: { studentId?: string; range?: string },
      ctx: StudentBffContext,
    ): Promise<unknown> {
      if (!ctx.userId) {
        throw new UnauthorizedError();
      }

      assertOwnData(ctx.userId, args.studentId);

      const range = args.range ?? "30d";
      const cacheKey = `${ctx.userId}:${range}`;
      const cached = await ctx.cache.get<unknown>("analytics:trend", cacheKey);
      if (cached) {
        return ok(cached, {
          traceId: ctx.traceId,
          cachedAt: new Date().toISOString(),
        });
      }

      try {
        const result = await ctx.downstream.call(
          "data-ana",
          "GetLearningTrend",
          {
            studentId: ctx.userId,
            range,
          },
          {
            traceId: ctx.traceId,
            metadata: { "x-user-id": ctx.userId },
          },
        );

        await ctx.cache.set(
          "analytics:trend",
          result,
          CacheTTL.ANALYTICS_TREND,
          cacheKey,
        );
        return ok(result, { traceId: ctx.traceId });
      } catch (err) {
        return fail(
          "BFF_STUDENT_BAD_GATEWAY",
          `Failed to fetch trend: ${(err as Error).message}`,
          { i18nKey: "error.bffStudent.bad_gateway", traceId: ctx.traceId },
        );
      }
    },
  },
};
