/**
 * MSW 请求处理器（ai14）
 *
 * 拦截 POST /api/v1/student/graphql，按 operationName 分发到对应的 mock 响应。
 * 所有响应包裹在 ActionState 信封中：
 *   { success: true, errors: [], data: <fixture>, extensions: { degraded: false } }
 *
 * GraphQL 响应结构：
 *   { data: { <operationName>: ActionState<...> } }
 *
 * 支持的 24 个操作（16 查询 + 8 变更）详见 types.ts OperationName。
 */

import { http, HttpResponse } from "msw";
import type {
  ActionState,
  MutationOperationName,
  QueryOperationName,
} from "../lib/graphql/types";
import { ERROR_CODES } from "../lib/graphql/types";

// 查询 fixture 数据
import currentUserFixture from "./fixtures/currentUser.json";
import myClassesFixture from "./fixtures/myClasses.json";
import myExamsFixture from "./fixtures/myExams.json";
import examDetailFixture from "./fixtures/examDetail.json";
import myHomeworkFixture from "./fixtures/myHomework.json";
import homeworkDetailFixture from "./fixtures/homeworkDetail.json";
import myGradesFixture from "./fixtures/myGrades.json";
import myAttendanceFixture from "./fixtures/myAttendance.json";
import textbooksFixture from "./fixtures/textbooks.json";
import chaptersFixture from "./fixtures/chapters.json";
import learningPathFixture from "./fixtures/learningPath.json";
import studentDashboardFixture from "./fixtures/studentDashboard.json";
import myWeaknessFixture from "./fixtures/myWeakness.json";
import myTrendFixture from "./fixtures/myTrend.json";
import myNotificationsFixture from "./fixtures/myNotifications.json";
import serverTimeFixture from "./fixtures/serverTime.json";
import myScheduleFixture from "./fixtures/mySchedule.json";
import studentGrowthFixture from "./fixtures/studentGrowth.json";
import assignmentAnalysisFixture from "./fixtures/assignmentAnalysis.json";
import myProfileFixture from "./fixtures/myProfile.json";
// 批次 A 扩展 fixture
import errorBookFixture from "./fixtures/errorBook.json";
import leaveRequestsFixture from "./fixtures/leaveRequests.json";
import electiveCoursesFixture from "./fixtures/electiveCourses.json";
import practiceSessionsFixture from "./fixtures/practiceSessions.json";
import announcementsFixture from "./fixtures/announcements.json";
import lessonPlansFixture from "./fixtures/lessonPlans.json";
import coursePlansFixture from "./fixtures/coursePlans.json";
import reportCardFixture from "./fixtures/reportCard.json";
import diagnosticReportsFixture from "./fixtures/diagnosticReports.json";
import masterySummaryFixture from "./fixtures/masterySummary.json";

// ---------------------------------------------------------------------------
// GraphQL 请求/响应类型
// ---------------------------------------------------------------------------

/** GraphQL 请求体 */
interface GraphQLRequest {
  query: string;
  variables?: Record<string, unknown>;
  operationName?: string;
}

/** GraphQL 顶层响应 */
interface GraphQLResponseData {
  data: Record<string, unknown> | null;
  errors?: Array<{ message: string; extensions?: Record<string, unknown> }>;
}

// ---------------------------------------------------------------------------
// ActionState 信封构造工具
// ---------------------------------------------------------------------------

/**
 * 构造成功的 ActionState 响应
 * @param data 业务数据
 * @returns ActionState 信封
 */
function ok<T>(data: T): ActionState<T> {
  return {
    success: true,
    errors: [],
    data,
    extensions: { degraded: false },
  };
}

/**
 * 构造失败的 ActionState 响应
 * @param code 错误码
 * @param message 错误消息
 * @returns ActionState 信封（data 为 null）
 */
function fail<T>(code: string, message: string): ActionState<T> {
  return {
    success: false,
    errors: [{ code, message }],
    data: null,
    extensions: { degraded: false },
  };
}

/**
 * 构造降级的 ActionState 响应（部分上游不可用）
 * @param data 部分业务数据
 * @param reason 降级原因
 * @returns ActionState 信封（degraded: true）
 */
function degraded<T>(data: T, reason: string): ActionState<T> {
  return {
    success: true,
    errors: [],
    data,
    extensions: { degraded: true, degradedReason: reason },
  };
}

// ---------------------------------------------------------------------------
// GraphQL 响应构造
// ---------------------------------------------------------------------------

/**
 * 构造 GraphQL 成功响应（单操作）
 * @param operationName 操作名
 * @param actionState ActionState 信封
 * @returns HttpResponse JSON
 */
function graphqlOk(
  operationName: string,
  actionState: ActionState<unknown>,
): Response {
  const body: GraphQLResponseData = {
    data: { [operationName]: actionState },
  };
  return HttpResponse.json(body);
}

/**
 * 构造 GraphQL 错误响应（顶层错误，如认证失败）
 * @param message 错误消息
 * @param code 错误码
 * @returns HttpResponse JSON
 */
function graphqlError(message: string, code: string): Response {
  const body: GraphQLResponseData = {
    data: null,
    errors: [{ message, extensions: { code } }],
  };
  return HttpResponse.json(body, { status: 200 });
}

// ---------------------------------------------------------------------------
// operationName 提取
// ---------------------------------------------------------------------------

/**
 * 从 GraphQL 请求中提取 operationName
 * 优先使用 body.operationName，缺失时从 query 字符串解析
 * @param body GraphQL 请求体
 * @returns 操作名或 null
 */
function extractOperationName(body: GraphQLRequest): string | null {
  if (body.operationName) {
    return body.operationName;
  }
  // 从 query 字符串解析：query/mutation OperationName( ...
  const match = body.query.match(/(?:query|mutation)\s+(\w+)/);
  return match?.[1] ?? null;
}

// ---------------------------------------------------------------------------
// 查询处理器（16 个）
// ---------------------------------------------------------------------------

/**
 * 处理查询操作
 * @param operationName 操作名
 * @param variables 查询变量
 * @returns HttpResponse
 */
function handleQuery(
  operationName: QueryOperationName,
  variables: Record<string, unknown>,
): Response {
  switch (operationName) {
    case "currentUser":
      return graphqlOk("currentUser", ok(currentUserFixture));

    case "myClasses":
      return graphqlOk("myClasses", ok(myClassesFixture));

    case "myExams":
      return graphqlOk("myExams", ok(myExamsFixture));

    case "examDetail": {
      const examId = variables["examId"] ?? "exam-001";
      // 根据请求的 examId 返回对应数据，默认返回 examDetail fixture
      const detail =
        examId === "exam-001"
          ? examDetailFixture
          : { ...examDetailFixture, id: examId };
      return graphqlOk("examDetail", ok(detail));
    }

    case "myHomework":
      return graphqlOk("myHomework", ok(myHomeworkFixture));

    case "homeworkDetail": {
      const homeworkId = variables["homeworkId"] ?? "hw-001";
      const detail =
        homeworkId === "hw-001"
          ? homeworkDetailFixture
          : { ...homeworkDetailFixture, id: homeworkId };
      return graphqlOk("homeworkDetail", ok(detail));
    }

    case "myGrades":
      return graphqlOk("myGrades", ok(myGradesFixture));

    case "myAttendance":
      return graphqlOk("myAttendance", ok(myAttendanceFixture));

    case "textbooks":
      return graphqlOk("textbooks", ok(textbooksFixture));

    case "chapters": {
      const textbookId = variables["textbookId"] ?? "tb-001";
      const chapters =
        textbookId === "tb-001"
          ? chaptersFixture
          : chaptersFixture.filter((c) => c.textbookId === textbookId);
      return graphqlOk("chapters", ok(chapters));
    }

    case "learningPath":
      return graphqlOk("learningPath", ok(learningPathFixture));

    case "studentDashboard":
      return graphqlOk("studentDashboard", ok(studentDashboardFixture));

    case "myWeakness":
      return graphqlOk("myWeakness", ok(myWeaknessFixture));

    case "myTrend":
      return graphqlOk("myTrend", ok(myTrendFixture));

    case "myNotifications": {
      const first = (variables["first"] as number | undefined) ?? 10;
      const items = myNotificationsFixture.slice(0, first);
      const unreadCount = items.filter((n) => !n.read).length;
      const result = {
        items,
        totalCount: myNotificationsFixture.length,
        unreadCount,
      };
      return graphqlOk("myNotifications", ok(result));
    }

    case "serverTime":
      // 返回当前时间以支持倒计时校正
      return graphqlOk(
        "serverTime",
        ok({
          timestamp: new Date().toISOString(),
          offset: 0,
        }),
      );

    case "mySchedule":
      return graphqlOk("mySchedule", ok(myScheduleFixture));

    case "studentGrowth":
      return graphqlOk("studentGrowth", ok(studentGrowthFixture));

    case "assignmentAnalysis": {
      const homeworkId = variables["homeworkId"] ?? "hw-001";
      const detail =
        homeworkId === assignmentAnalysisFixture.homeworkId
          ? assignmentAnalysisFixture
          : { ...assignmentAnalysisFixture, homeworkId: homeworkId as string };
      return graphqlOk("assignmentAnalysis", ok(detail));
    }

    case "myProfile":
      return graphqlOk("myProfile", ok(myProfileFixture));

    // === 批次 A 扩展查询 ===
    case "myErrorBook":
      return graphqlOk("myErrorBook", ok(errorBookFixture));

    case "myLeaveRequests":
      return graphqlOk("myLeaveRequests", ok(leaveRequestsFixture));

    case "myElectiveSelections": {
      // 从可选课程中派生选课记录
      const selections = electiveCoursesFixture.slice(0, 2).map((c) => ({
        id: `sel-${c.id}`,
        courseId: c.id,
        courseName: c.name,
        status: "enrolled" as const,
        selectedAt: "2026-07-02T10:00:00.000Z",
        enrolledAt: "2026-07-03T08:00:00.000Z",
        droppedAt: null,
        dropReason: null,
        course: {
          id: c.id,
          name: c.name,
          teacherName: c.teacherName,
          subjectName: c.subjectName,
          capacity: c.capacity,
          enrolledCount: c.enrolledCount,
          classroom: c.classroom,
          schedule: c.schedule,
          credit: c.credit,
          status: c.status,
        },
      }));
      return graphqlOk("myElectiveSelections", ok(selections));
    }

    case "availableElectiveCourses":
      return graphqlOk(
        "availableElectiveCourses",
        ok(electiveCoursesFixture),
      );

    case "myPracticeSessions":
      return graphqlOk("myPracticeSessions", ok(practiceSessionsFixture));

    case "startPracticeSession": {
      const input = (variables["input"] ?? {}) as Record<string, unknown>;
      const practiceType = (input["practiceType"] as string) ?? "error_variant";
      const session = {
        id: `ps-${Date.now()}`,
        practiceType,
        status: "in_progress" as const,
        totalQuestions: 10,
        answeredQuestions: 0,
        correctCount: 0,
        accuracy: 0,
        startedAt: new Date().toISOString(),
        currentQuestionIndex: 0,
        questions: [
          {
            id: "pq-001",
            questionId: "q-001",
            content: "已知函数 f(x) = x² - 2x + 1，求 f(x) 的最小值。",
            type: "short-answer",
            options: [],
            maxScore: 5,
            status: "pending" as const,
          },
          {
            id: "pq-002",
            questionId: "q-002",
            content: "下列哪个是二次函数的标准形式？",
            type: "single-choice",
            options: [
              { id: "opt-a", text: "y = ax + b" },
              { id: "opt-b", text: "y = ax² + bx + c (a≠0)" },
              { id: "opt-c", text: "y = a/x" },
              { id: "opt-d", text: "y = √x" },
            ],
            maxScore: 5,
            status: "pending" as const,
          },
        ],
      };
      return graphqlOk("startPracticeSession", ok({ session }));
    }

    case "announcements":
      return graphqlOk("announcements", ok(announcementsFixture));

    case "announcementDetail": {
      const announcementId =
        (variables["announcementId"] as string) ?? "an-001";
      const detail =
        announcementsFixture.find((a) => a.id === announcementId) ??
        announcementsFixture[0];
      return graphqlOk("announcementDetail", ok(detail));
    }

    case "myLessonPlans":
      return graphqlOk("myLessonPlans", ok(lessonPlansFixture));

    case "lessonPlanDetail": {
      const planId = (variables["planId"] as string) ?? "lp-001";
      const item =
        lessonPlansFixture.find((l) => l.id === planId) ?? lessonPlansFixture[0];
      const detail = {
        ...item,
        content: {
          objectives:
            "1. 理解核心概念与基本原理\n2. 掌握解题方法与技巧\n3. 能够综合运用解决实际问题",
          keyPoints: "重点：核心公式的推导与应用\n难点：综合题型的分析与解题策略",
          summary: "本节课围绕核心知识点展开，通过例题讲解与课堂练习巩固理解。",
          homework: "完成课后练习第 1-5 题，预习下一节内容。",
          blackboard: "板书要点：公式推导流程图 + 例题解题步骤",
        },
      };
      return graphqlOk("lessonPlanDetail", ok(detail));
    }

    case "myCoursePlans":
      return graphqlOk("myCoursePlans", ok(coursePlansFixture));

    case "coursePlanDetail": {
      const planId = (variables["planId"] as string) ?? "cp-001";
      const item =
        coursePlansFixture.find((c) => c.id === planId) ?? coursePlansFixture[0];
      const detail = {
        ...item,
        items: [
          {
            id: "cpi-001",
            week: 1,
            topic: "函数的基本概念",
            content: "函数定义、定义域、值域、表示方法",
            hours: 4,
            textbookChapter: "第 1.1 节",
            notes: null,
            isCompleted: true,
            completedAt: "2026-02-23T16:00:00.000Z",
          },
          {
            id: "cpi-002",
            week: 2,
            topic: "函数的单调性与奇偶性",
            content: "单调性判定、奇偶性判定、综合应用",
            hours: 4,
            textbookChapter: "第 1.2-1.3 节",
            notes: "注意数形结合",
            isCompleted: true,
            completedAt: "2026-03-02T16:00:00.000Z",
          },
          {
            id: "cpi-013",
            week: 13,
            topic: "期末复习与综合训练",
            content: "全册知识点梳理、模拟试卷讲评",
            hours: 4,
            textbookChapter: "复习章节",
            notes: null,
            isCompleted: false,
            completedAt: null,
          },
        ],
      };
      return graphqlOk("coursePlanDetail", ok(detail));
    }

    case "myReportCard":
      return graphqlOk("myReportCard", ok(reportCardFixture));

    case "myDiagnosticReports":
      return graphqlOk("myDiagnosticReports", ok(diagnosticReportsFixture));

    case "myMasterySummary":
      return graphqlOk("myMasterySummary", ok(masterySummaryFixture));

    default: {
      // 未覆盖的查询操作名，返回错误
      return graphqlError(
        `未实现的查询: ${operationName}`,
        ERROR_CODES.BFF_STUDENT_NOT_FOUND,
      );
    }
  }
}

// ---------------------------------------------------------------------------
// 变更处理器（8 个）
// ---------------------------------------------------------------------------

/**
 * 处理变更操作
 * @param operationName 操作名
 * @param variables 变更变量
 * @returns HttpResponse
 */
function handleMutation(
  operationName: MutationOperationName,
  variables: Record<string, unknown>,
): Response {
  switch (operationName) {
    case "submitHomework": {
      const homeworkId = variables["homeworkId"] ?? "hw-001";
      const result = {
        submissionId: `submission-${Date.now()}`,
        submittedAt: new Date().toISOString(),
      };
      void homeworkId;
      return graphqlOk("submitHomework", ok(result));
    }

    case "submitExam": {
      const examId = variables["examId"] ?? "exam-001";
      const result = {
        submissionId: `submission-${Date.now()}`,
        submittedAt: new Date().toISOString(),
        score: 85,
        maxScore: 100,
      };
      void examId;
      return graphqlOk("submitExam", ok(result));
    }

    case "saveExamDraft": {
      const result = {
        savedAt: new Date().toISOString(),
        ok: true,
      };
      return graphqlOk("saveExamDraft", ok(result));
    }

    case "markAsRead": {
      const notificationId = variables["notificationId"] ?? "";
      const result = {
        notificationId: notificationId as string,
        read: true,
      };
      return graphqlOk("markAsRead", ok(result));
    }

    case "markAllAsRead": {
      const result = {
        updatedCount: myNotificationsFixture.filter((n) => !n.read).length,
      };
      return graphqlOk("markAllAsRead", ok(result));
    }

    case "recordExamViolation": {
      const result = {
        recorded: true,
        violationCount: 1,
      };
      return graphqlOk("recordExamViolation", ok(result));
    }

    case "recordPasteEvent": {
      const result = {
        recorded: true,
      };
      return graphqlOk("recordPasteEvent", ok(result));
    }

    case "updateNotificationPreference": {
      const type = variables["type"] ?? "system";
      const enabled = variables["enabled"] ?? true;
      const result = {
        type: type as string,
        enabled: enabled as boolean,
        updatedAt: new Date().toISOString(),
      };
      return graphqlOk("updateNotificationPreference", ok(result));
    }

    case "updateProfile": {
      const input = (variables["input"] ?? {}) as Record<string, unknown>;
      const result = {
        id: myProfileFixture.id,
        name: (input["name"] as string) ?? myProfileFixture.name,
        email: (input["email"] as string) ?? myProfileFixture.email,
        phone: (input["phone"] as string) ?? myProfileFixture.phone,
        gender: (input["gender"] as string) ?? myProfileFixture.gender,
        bio: (input["bio"] as string) ?? myProfileFixture.bio,
        preferredSubjectId:
          (input["preferredSubjectId"] as string) ??
          myProfileFixture.preferredSubjectId,
      };
      return graphqlOk("updateProfile", ok(result));
    }

    case "changePassword": {
      return graphqlOk("changePassword", ok({ ok: true }));
    }

    case "requestExtension": {
      const input = (variables["input"] ?? {}) as Record<string, unknown>;
      const homeworkId =
        (input["homeworkId"] as string) ?? "hw-001";
      const reason = (input["reason"] as string) ?? "";
      const newDue = new Date();
      newDue.setDate(newDue.getDate() + 2);
      const result = {
        homeworkId,
        approved: true,
        newDueDate: newDue.toISOString(),
        reason,
      };
      return graphqlOk("requestExtension", ok(result));
    }

    case "joinClass": {
      const input = (variables["input"] ?? {}) as Record<string, unknown>;
      const inviteCode = (input["inviteCode"] as string) ?? "";
      if (inviteCode.length !== 6) {
        return graphqlOk(
          "joinClass",
          fail(ERROR_CODES.BFF_STUDENT_VALIDATION_FAILED, "邀请码必须为 6 位"),
        );
      }
      const result = {
        classId: `class-${Date.now()}`,
        className: "高三(3)班",
        grade: "高三",
        inviteCode,
      };
      return graphqlOk("joinClass", ok(result));
    }

    case "leaveClass": {
      const input = (variables["input"] ?? {}) as Record<string, unknown>;
      const classId = (input["classId"] as string) ?? "";
      const result = { classId, ok: true };
      return graphqlOk("leaveClass", ok(result));
    }

    // === 批次 A 扩展变更 ===
    case "addErrorBookItem": {
      const input = (variables["input"] ?? {}) as Record<string, unknown>;
      const result = {
        id: `eb-${Date.now()}`,
        status: "new" as const,
        createdAt: new Date().toISOString(),
      };
      void input;
      return graphqlOk("addErrorBookItem", ok(result));
    }

    case "updateErrorBookItem": {
      const input = (variables["input"] ?? {}) as Record<string, unknown>;
      const id = (input["id"] as string) ?? "";
      const reviewResult = input["reviewResult"] as
        | "again"
        | "hard"
        | "good"
        | "easy"
        | undefined;
      const masteryMap: Record<string, number> = {
        again: 0.2,
        hard: 0.4,
        good: 0.7,
        easy: 0.9,
      };
      const mastery = reviewResult ? masteryMap[reviewResult] ?? 0.5 : 0.5;
      const nextReview = new Date();
      nextReview.setDate(nextReview.getDate() + (reviewResult === "again" ? 1 : reviewResult === "hard" ? 3 : 7));
      const result = {
        id,
        status: mastery >= 0.8 ? ("mastered" as const) : ("learning" as const),
        masteryLevel: mastery,
        nextReviewAt: nextReview.toISOString(),
        reviewCount: 1,
      };
      return graphqlOk("updateErrorBookItem", ok(result));
    }

    case "deleteErrorBookItem": {
      const input = (variables["input"] ?? {}) as Record<string, unknown>;
      const id = (input["id"] as string) ?? "";
      return graphqlOk("deleteErrorBookItem", ok({ id, deleted: true }));
    }

    case "createLeaveRequest": {
      const input = (variables["input"] ?? {}) as Record<string, unknown>;
      const result = {
        id: `lv-${Date.now()}`,
        status: "pending" as const,
        createdAt: new Date().toISOString(),
      };
      void input;
      return graphqlOk("createLeaveRequest", ok(result));
    }

    case "cancelLeaveRequest": {
      const input = (variables["input"] ?? {}) as Record<string, unknown>;
      const id = (input["id"] as string) ?? "";
      return graphqlOk(
        "cancelLeaveRequest",
        ok({ id, status: "cancelled" as const }),
      );
    }

    case "selectElectiveCourse": {
      const input = (variables["input"] ?? {}) as Record<string, unknown>;
      const courseId = (input["courseId"] as string) ?? "";
      const result = {
        id: `sel-${Date.now()}`,
        courseId,
        status: "enrolled" as const,
        selectedAt: new Date().toISOString(),
      };
      return graphqlOk("selectElectiveCourse", ok(result));
    }

    case "dropElectiveCourse": {
      const input = (variables["input"] ?? {}) as Record<string, unknown>;
      const courseId = (input["courseId"] as string) ?? "";
      const result = {
        id: `sel-${courseId}`,
        courseId,
        status: "dropped" as const,
        droppedAt: new Date().toISOString(),
      };
      return graphqlOk("dropElectiveCourse", ok(result));
    }

    case "submitPracticeAnswer": {
      const input = (variables["input"] ?? {}) as Record<string, unknown>;
      const questionId = (input["questionId"] as string) ?? "";
      const isCorrect = questionId === "q-002" && input["answer"] === "opt-b";
      const result = {
        answerId: `ans-${Date.now()}`,
        isCorrect,
        score: isCorrect ? 5 : 0,
        maxScore: 5,
        correctAnswer: questionId === "q-002" ? "opt-b" : "x=1",
        sessionCompleted: false,
        session: {
          id: (input["sessionId"] as string) ?? "",
          answeredQuestions: 1,
          correctCount: isCorrect ? 1 : 0,
          accuracy: isCorrect ? 1 : 0,
          status: "in_progress" as const,
        },
      };
      return graphqlOk("submitPracticeAnswer", ok(result));
    }

    case "markAnnouncementRead": {
      const input = (variables["input"] ?? {}) as Record<string, unknown>;
      const announcementId = (input["announcementId"] as string) ?? "";
      return graphqlOk(
        "markAnnouncementRead",
        ok({ announcementId, read: true }),
      );
    }

    default: {
      // 未覆盖的变更操作名，返回错误
      return graphqlError(
        `未实现的变更: ${operationName}`,
        ERROR_CODES.BFF_STUDENT_NOT_FOUND,
      );
    }
  }
}

// ---------------------------------------------------------------------------
// 主处理器
// ---------------------------------------------------------------------------

/** 查询操作名集合 */
const QUERY_NAMES = new Set<QueryOperationName>([
  "currentUser",
  "myClasses",
  "myExams",
  "examDetail",
  "myHomework",
  "homeworkDetail",
  "myGrades",
  "myAttendance",
  "textbooks",
  "chapters",
  "learningPath",
  "studentDashboard",
  "myWeakness",
  "myTrend",
  "myNotifications",
  "serverTime",
  "mySchedule",
  "studentGrowth",
  "assignmentAnalysis",
  "myProfile",
  "myErrorBook",
  "myLeaveRequests",
  "myElectiveSelections",
  "availableElectiveCourses",
  "myPracticeSessions",
  "startPracticeSession",
  "announcements",
  "announcementDetail",
  "myLessonPlans",
  "lessonPlanDetail",
  "myCoursePlans",
  "coursePlanDetail",
  "myReportCard",
  "myDiagnosticReports",
  "myMasterySummary",
]);

/** 变更操作名集合 */
const MUTATION_NAMES = new Set<MutationOperationName>([
  "submitHomework",
  "submitExam",
  "saveExamDraft",
  "markAsRead",
  "markAllAsRead",
  "recordExamViolation",
  "recordPasteEvent",
  "updateNotificationPreference",
  "updateProfile",
  "changePassword",
  "requestExtension",
  "joinClass",
  "leaveClass",
]);

/**
 * 判断是否为查询操作名
 * @param name 操作名
 * @returns 是否查询
 */
function isQueryName(name: string): name is QueryOperationName {
  return (QUERY_NAMES as Set<string>).has(name);
}

/**
 * 判断是否为变更操作名
 * @param name 操作名
 * @returns 是否变更
 */
function isMutationName(name: string): name is MutationOperationName {
  return (MUTATION_NAMES as Set<string>).has(name);
}

/** MSW 请求处理器列表 */
export const handlers = [
  http.post(
    "*/api/v1/student/graphql",
    async ({ request }): Promise<Response> => {
      let body: GraphQLRequest;
      try {
        body = (await request.json()) as GraphQLRequest;
      } catch {
        return graphqlError(
          "请求体解析失败",
          ERROR_CODES.BFF_STUDENT_VALIDATION_FAILED,
        );
      }

      const operationName = extractOperationName(body);
      if (!operationName) {
        return graphqlError(
          "无法识别 operationName",
          ERROR_CODES.BFF_STUDENT_VALIDATION_FAILED,
        );
      }

      const variables = body.variables ?? {};

      // 按操作类型分发
      if (isQueryName(operationName)) {
        return handleQuery(operationName, variables);
      }

      if (isMutationName(operationName)) {
        return handleMutation(operationName, variables);
      }

      // 未知操作名
      return graphqlError(
        `未知操作: ${operationName}`,
        ERROR_CODES.BFF_STUDENT_VALIDATION_FAILED,
      );
    },
  ),
];

/** 导出 fixture 数据供测试使用 */
export const fixtures = {
  currentUser: currentUserFixture,
  myClasses: myClassesFixture,
  myExams: myExamsFixture,
  examDetail: examDetailFixture,
  myHomework: myHomeworkFixture,
  homeworkDetail: homeworkDetailFixture,
  myGrades: myGradesFixture,
  myAttendance: myAttendanceFixture,
  textbooks: textbooksFixture,
  chapters: chaptersFixture,
  learningPath: learningPathFixture,
  studentDashboard: studentDashboardFixture,
  myWeakness: myWeaknessFixture,
  myTrend: myTrendFixture,
  myNotifications: myNotificationsFixture,
  serverTime: serverTimeFixture,
  mySchedule: myScheduleFixture,
  studentGrowth: studentGrowthFixture,
  assignmentAnalysis: assignmentAnalysisFixture,
  myProfile: myProfileFixture,
  errorBook: errorBookFixture,
  leaveRequests: leaveRequestsFixture,
  electiveCourses: electiveCoursesFixture,
  practiceSessions: practiceSessionsFixture,
  announcements: announcementsFixture,
  lessonPlans: lessonPlansFixture,
  coursePlans: coursePlansFixture,
  reportCard: reportCardFixture,
  diagnosticReports: diagnosticReportsFixture,
  masterySummary: masterySummaryFixture,
};

/** 导出工具函数供测试使用 */
export { ok, fail, degraded, graphqlOk, graphqlError };

/** 导出操作名集合供测试断言 */
export { QUERY_NAMES, MUTATION_NAMES };
