/**
 * MSW Handlers
 *
 * 仲裁 ARB-004 §4：MSW 拦截所有 GraphQL/HTTP 请求
 * 端点：
 * - POST /api/auth/login - mock 登录
 * - POST /api/admin/graphql - admin 命名空间 GraphQL
 * - GET /ws - WebSocket（mock-socket 在 use-websocket.ts 中处理）
 */
import { graphql, http, HttpResponse } from "msw";
import {
  mockCurrentUser,
  mockUsers,
  mockRoles,
  mockPermissions,
  mockViewports,
  mockOrganization,
  mockClasses,
  mockTeachers,
  mockStudents,
  mockAuditLogs,
  mockDashboard,
  mockSystemSettings,
  mockSchools,
  mockGrades,
  mockGradeInsights,
  mockDepartments,
  mockAcademicYears,
  mockAuditOverviewStats,
  mockAuditTrend,
  mockDataChangeLogs,
  mockLoginLogs,
  mockAnnouncements,
  mockInvitationCodes,
  mockFiles,
  mockFileStats,
  mockAiProviders,
  mockAiUsage,
  mockSecurityPolicy,
  mockFileUploadConfig,
  mockNotificationConfig,
  mockBrandConfig,
  genId,
} from "./fixtures";
import type {
  UserViewModel,
  RoleViewModel,
  ViewportConfigViewModel,
  PaginatedResult,
  ListFilter,
} from "@/types/view-models";

const BASE_URL = "";

// 内存中可变副本（支持 mock 增删改）
const db = {
  users: [...mockUsers] as UserViewModel[],
  roles: [...mockRoles] as RoleViewModel[],
  viewports: [...mockViewports] as ViewportConfigViewModel[],
  permissions: [...mockPermissions],
  organization: [...mockOrganization],
  classes: [...mockClasses],
  teachers: [...mockTeachers],
  students: [...mockStudents],
  auditLogs: [...mockAuditLogs],
  systemSettings: { ...mockSystemSettings },
  schools: [...mockSchools],
  grades: [...mockGrades],
  departments: [...mockDepartments],
  academicYears: [...mockAcademicYears],
  announcements: [...mockAnnouncements],
  invitationCodes: [...mockInvitationCodes],
  files: [...mockFiles],
  aiProviders: [...mockAiProviders],
  securityPolicy: { ...mockSecurityPolicy },
  fileUploadConfig: { ...mockFileUploadConfig },
  notificationConfig: { ...mockNotificationConfig },
  brandConfig: { ...mockBrandConfig },
};

function paginate<T>(
  items: T[],
  filter: Partial<ListFilter>,
): PaginatedResult<T> {
  const page = filter.page ?? 1;
  const pageSize = filter.pageSize ?? 20;
  const start = (page - 1) * pageSize;
  const end = start + pageSize;
  const sliced = items.slice(start, end);
  return {
    items: sliced,
    total: items.length,
    page,
    pageSize,
    hasNext: end < items.length,
  };
}

function recordAudit(
  action: string,
  resourceType: string,
  resourceId: string,
  afterState?: string,
): void {
  db.auditLogs.unshift({
    id: genId("al"),
    eventId: genId("evt"),
    occurredAt: Date.now(),
    actorUserId: mockCurrentUser.id,
    actorName: mockCurrentUser.name,
    action,
    resourceType,
    resourceId,
    ip: "127.0.0.1",
    userAgent: "MSW-Mock",
    beforeState: null,
    afterState: afterState ?? null,
    traceId: genId("trace"),
  });
}

export const handlers = [
  // ─── 认证 ────────────────────────────────────────────
  http.post(`${BASE_URL}/api/auth/login`, async ({ request }) => {
    const body = (await request.json()) as { email: string; password: string };
    if (body.email === "admin@edu.test" && body.password === "admin123") {
      return HttpResponse.json({
        success: true,
        data: {
          user: mockCurrentUser,
          tokens: { accessToken: "mock-jwt-token-admin-001" },
        },
      });
    }
    return HttpResponse.json(
      {
        success: false,
        error: { message: "邮箱或密码错误" },
      },
      { status: 401 },
    );
  }),

  // ─── GraphQL admin 命名空间 ──────────────────────────
  graphql.operation(({ query, variables }) => {
    const operationName =
      (query.match(/^\s*(query|mutation)\s+(\w+)/) || [])[2] ?? "";

    // ── currentUser ──
    if (operationName === "CurrentUser") {
      return HttpResponse.json({ data: { currentUser: mockCurrentUser } });
    }

    // ── adminUsers ──
    if (operationName === "AdminUsers") {
      const filter = (variables.filter ?? {}) as Partial<ListFilter>;
      let items = [...db.users];
      if (filter.search) {
        const q = filter.search.toLowerCase();
        items = items.filter(
          (u) =>
            u.name.toLowerCase().includes(q) ||
            u.email.toLowerCase().includes(q),
        );
      }
      if (filter.status && filter.status !== "all") {
        items = items.filter((u) => u.status === filter.status);
      }
      const result = paginate(items, filter);
      return HttpResponse.json({ data: { adminUsers: result } });
    }

    // ── adminUser ──
    if (operationName === "AdminUser") {
      const id = variables.id as string;
      const user = db.users.find((u) => u.id === id) ?? null;
      return HttpResponse.json({ data: { adminUser: user } });
    }

    // ── createUser ──
    if (operationName === "CreateUser") {
      const input = variables.input as {
        email: string;
        name: string;
        password: string;
        roleIds?: string[];
        dataScope?: string;
        organizationId?: string;
      };
      const roles = db.roles.filter((r) => input.roleIds?.includes(r.id));
      const newUser: UserViewModel = {
        id: genId("u"),
        email: input.email,
        name: input.name,
        roles,
        status: "active",
        dataScope: (input.dataScope as UserViewModel["dataScope"]) ?? "SCHOOL",
        organizationId: input.organizationId ?? null,
        schoolName: "Edu 实验学校",
        lastLoginAt: null,
        createdAt: Date.now(),
        updatedAt: Date.now(),
      };
      db.users.push(newUser);
      recordAudit(
        "USER_CREATE",
        "iam.user",
        newUser.id,
        JSON.stringify({ email: newUser.email, name: newUser.name }),
      );
      return HttpResponse.json({
        data: {
          createUser: {
            id: newUser.id,
            email: newUser.email,
            name: newUser.name,
            status: newUser.status,
          },
        },
      });
    }

    // ── updateUser ──
    if (operationName === "UpdateUser") {
      const id = variables.id as string;
      const input = variables.input as {
        name?: string;
        email?: string;
        roleIds?: string[];
        dataScope?: string;
        organizationId?: string;
      };
      const user = db.users.find((u) => u.id === id);
      if (!user) {
        return HttpResponse.json(
          { errors: [{ message: "用户不存在" }] },
          { status: 404 },
        );
      }
      if (input.name) user.name = input.name;
      if (input.email) user.email = input.email;
      if (input.roleIds)
        user.roles = db.roles.filter((r) => input.roleIds!.includes(r.id));
      if (input.dataScope)
        user.dataScope = input.dataScope as UserViewModel["dataScope"];
      if (input.organizationId !== undefined)
        user.organizationId = input.organizationId;
      user.updatedAt = Date.now();
      recordAudit("USER_UPDATE", "iam.user", user.id, JSON.stringify(input));
      return HttpResponse.json({
        data: {
          updateUser: {
            id: user.id,
            email: user.email,
            name: user.name,
            status: user.status,
          },
        },
      });
    }

    // ── toggleUserStatus ──
    if (operationName === "ToggleUserStatus") {
      const id = variables.id as string;
      const newStatus = variables.status as UserViewModel["status"];
      const user = db.users.find((u) => u.id === id);
      if (!user) {
        return HttpResponse.json(
          { errors: [{ message: "用户不存在" }] },
          { status: 404 },
        );
      }
      const before = user.status;
      user.status = newStatus;
      user.updatedAt = Date.now();
      recordAudit(
        "USER_TOGGLE_STATUS",
        "iam.user",
        user.id,
        JSON.stringify({ before, after: newStatus }),
      );
      return HttpResponse.json({
        data: { toggleUserStatus: { id: user.id, status: user.status } },
      });
    }

    // ── adminRoles ──
    if (operationName === "AdminRoles") {
      return HttpResponse.json({ data: { adminRoles: db.roles } });
    }

    // ── createRole ──
    if (operationName === "CreateRole") {
      const input = variables.input as {
        name: string;
        code: string;
        description?: string;
        dataScope?: string;
      };
      const newRole: RoleViewModel = {
        id: genId("r"),
        name: input.name,
        code: input.code,
        description: input.description ?? "",
        permissions: [],
        userCount: 0,
        dataScope: (input.dataScope as RoleViewModel["dataScope"]) ?? "SCHOOL",
        isSystem: false,
        createdAt: Date.now(),
        updatedAt: Date.now(),
      };
      db.roles.push(newRole);
      recordAudit(
        "ROLE_CREATE",
        "iam.role",
        newRole.id,
        JSON.stringify({ name: newRole.name, code: newRole.code }),
      );
      return HttpResponse.json({
        data: {
          createRole: {
            id: newRole.id,
            name: newRole.name,
            code: newRole.code,
          },
        },
      });
    }

    // ── updateRolePermissions ──
    if (operationName === "UpdateRolePermissions") {
      const roleId = variables.roleId as string;
      const codes = variables.permissionCodes as string[];
      const role = db.roles.find((r) => r.id === roleId);
      if (!role) {
        return HttpResponse.json(
          { errors: [{ message: "角色不存在" }] },
          { status: 404 },
        );
      }
      role.permissions = db.permissions.filter((p) => codes.includes(p.code));
      role.updatedAt = Date.now();
      recordAudit(
        "ROLE_UPDATE",
        "iam.role",
        role.id,
        JSON.stringify({ permissionCodes: codes }),
      );
      return HttpResponse.json({
        data: {
          updateRolePermissions: {
            id: role.id,
            permissions: role.permissions.map((p) => ({
              id: p.id,
              code: p.code,
            })),
          },
        },
      });
    }

    // ── adminPermissions ──
    if (operationName === "AdminPermissions") {
      return HttpResponse.json({ data: { adminPermissions: db.permissions } });
    }

    // ── adminViewports ──
    if (operationName === "AdminViewports") {
      const scope = variables.scope as string | undefined;
      const items = scope
        ? db.viewports.filter((v) => v.scope === scope)
        : db.viewports;
      return HttpResponse.json({ data: { adminViewports: items } });
    }

    // ── updateViewport ──
    if (operationName === "UpdateViewport") {
      const id = variables.id as string;
      const input = variables.input as {
        label?: string;
        sortOrder?: number;
        isVisible?: boolean;
        requiredPermission?: string | null;
      };
      const vp = db.viewports.find((v) => v.id === id);
      if (!vp) {
        return HttpResponse.json(
          { errors: [{ message: "视口不存在" }] },
          { status: 404 },
        );
      }
      if (input.label !== undefined) vp.label = input.label;
      if (input.sortOrder !== undefined) vp.sortOrder = input.sortOrder;
      if (input.isVisible !== undefined) vp.isVisible = input.isVisible;
      if (input.requiredPermission !== undefined)
        vp.requiredPermission = input.requiredPermission;
      recordAudit(
        "VIEWPORT_UPDATE",
        "iam.viewport",
        vp.id,
        JSON.stringify(input),
      );
      return HttpResponse.json({
        data: {
          updateViewport: {
            id: vp.id,
            key: vp.key,
            label: vp.label,
            sortOrder: vp.sortOrder,
            isVisible: vp.isVisible,
          },
        },
      });
    }

    // ── adminOrganization ──
    if (operationName === "AdminOrganization") {
      const parentId = variables.parentId as string | null | undefined;
      const items =
        parentId === undefined || parentId === null
          ? db.organization.filter((n) => n.parentId === null)
          : db.organization.filter((n) => n.parentId === parentId);
      return HttpResponse.json({ data: { adminOrganization: items } });
    }

    // ── adminClasses ──
    if (operationName === "AdminClasses") {
      const filter = (variables.filter ?? {}) as Partial<ListFilter>;
      let items = [...db.classes];
      if (filter.search) {
        const q = filter.search.toLowerCase();
        items = items.filter(
          (c) =>
            c.name.toLowerCase().includes(q) ||
            c.gradeName.toLowerCase().includes(q),
        );
      }
      if (filter.schoolId) {
        // mock：单一学校
      }
      const result = paginate(items, filter);
      return HttpResponse.json({ data: { adminClasses: result } });
    }

    // ── adminTeachers ──
    if (operationName === "AdminTeachers") {
      const filter = (variables.filter ?? {}) as Partial<ListFilter>;
      let items = [...db.teachers];
      if (filter.search) {
        const q = filter.search.toLowerCase();
        items = items.filter(
          (t) =>
            t.name.toLowerCase().includes(q) ||
            t.email.toLowerCase().includes(q),
        );
      }
      if (filter.status && filter.status !== "all") {
        items = items.filter((t) => t.status === filter.status);
      }
      const result = paginate(items, filter);
      return HttpResponse.json({ data: { adminTeachers: result } });
    }

    // ── adminStudents ──
    if (operationName === "AdminStudents") {
      const filter = (variables.filter ?? {}) as Partial<ListFilter>;
      let items = [...db.students];
      if (filter.search) {
        const q = filter.search.toLowerCase();
        items = items.filter(
          (s) =>
            s.name.toLowerCase().includes(q) ||
            s.email.toLowerCase().includes(q),
        );
      }
      if (filter.status && filter.status !== "all") {
        items = items.filter((s) => s.status === filter.status);
      }
      const result = paginate(items, filter);
      return HttpResponse.json({ data: { adminStudents: result } });
    }

    // ── auditLogs ──
    if (operationName === "AuditLogs") {
      const filter = (variables.filter ?? {}) as Partial<ListFilter> & {
        action?: string;
        actorUserId?: string;
      };
      let items = [...db.auditLogs];
      if (filter.search) {
        const q = filter.search.toLowerCase();
        items = items.filter(
          (l) =>
            l.actorName.toLowerCase().includes(q) ||
            l.action.toLowerCase().includes(q) ||
            l.resourceType.toLowerCase().includes(q),
        );
      }
      if (filter.action) {
        items = items.filter((l) => l.action === filter.action);
      }
      if (filter.actorUserId) {
        items = items.filter((l) => l.actorUserId === filter.actorUserId);
      }
      const result = paginate(items, filter);
      return HttpResponse.json({ data: { auditLogs: result } });
    }

    // ── adminDashboard ──
    if (operationName === "AdminDashboard") {
      return HttpResponse.json({ data: { adminDashboard: mockDashboard } });
    }

    // ── systemSettings ──
    if (operationName === "SystemSettings") {
      return HttpResponse.json({ data: { systemSettings: db.systemSettings } });
    }

    // ── updateSystemSettings ──
    if (operationName === "UpdateSystemSettings") {
      const input = variables.input as Partial<typeof mockSystemSettings>;
      Object.assign(db.systemSettings, input);
      recordAudit(
        "SYSTEM_SETTINGS_UPDATE",
        "admin.system",
        "settings",
        JSON.stringify(input),
      );
      return HttpResponse.json({
        data: {
          updateSystemSettings: {
            schoolName: db.systemSettings.schoolName,
            schoolCode: db.systemSettings.schoolCode,
            academicYear: db.systemSettings.academicYear,
            semester: db.systemSettings.semester,
          },
        },
      });
    }

    // ── auditOverviewStats ──
    if (operationName === "AuditOverviewStats") {
      return HttpResponse.json({
        data: { auditOverviewStats: mockAuditOverviewStats },
      });
    }

    // ── auditTrend ──
    if (operationName === "AuditTrend") {
      return HttpResponse.json({ data: { auditTrend: mockAuditTrend } });
    }

    // ── dataChangeLogs ──
    if (operationName === "DataChangeLogs") {
      return HttpResponse.json({
        data: {
          dataChangeLogs: paginate(mockDataChangeLogs, variables.filter ?? {}),
        },
      });
    }

    // ── loginLogs ──
    if (operationName === "LoginLogs") {
      return HttpResponse.json({
        data: { loginLogs: paginate(mockLoginLogs, variables.filter ?? {}) },
      });
    }

    // ── adminSchools ──
    if (operationName === "AdminSchools") {
      return HttpResponse.json({ data: { adminSchools: db.schools } });
    }

    // ── adminGrades ──
    if (operationName === "AdminGrades") {
      const schoolId = variables.schoolId;
      const grades = schoolId
        ? db.grades.filter((g) => g.schoolId === schoolId)
        : db.grades;
      return HttpResponse.json({ data: { adminGrades: grades } });
    }

    // ── adminGradeInsights ──
    if (operationName === "AdminGradeInsights") {
      return HttpResponse.json({
        data: { adminGradeInsights: mockGradeInsights },
      });
    }

    // ── adminDepartments ──
    if (operationName === "AdminDepartments") {
      const schoolId = variables.schoolId;
      const depts = schoolId
        ? db.departments.filter((d) => d.schoolId === schoolId)
        : db.departments;
      return HttpResponse.json({ data: { adminDepartments: depts } });
    }

    // ── adminAcademicYears ──
    if (operationName === "AdminAcademicYears") {
      return HttpResponse.json({
        data: { adminAcademicYears: db.academicYears },
      });
    }

    // ── adminAnnouncements ──
    if (operationName === "AdminAnnouncements") {
      return HttpResponse.json({
        data: {
          adminAnnouncements: paginate(
            db.announcements,
            variables.filter ?? {},
          ),
        },
      });
    }

    // ── createAnnouncement ──
    if (operationName === "CreateAnnouncement") {
      const input = variables.input;
      const newAnn = {
        id: genId("ann"),
        title: input.title,
        content: input.content,
        status: "draft" as const,
        audience: input.audience ?? ["all"],
        authorName: mockCurrentUser.name,
        isPinned: false,
        readCount: 0,
        totalCount: 0,
        publishedAt: null,
        createdAt: Date.now(),
        updatedAt: Date.now(),
      };
      db.announcements.unshift(newAnn);
      recordAudit("ANNOUNCEMENT_CREATE", "announcement", newAnn.id);
      return HttpResponse.json({
        data: {
          createAnnouncement: {
            id: newAnn.id,
            title: newAnn.title,
            status: newAnn.status,
          },
        },
      });
    }

    // ── publishAnnouncement ──
    if (operationName === "PublishAnnouncement") {
      const ann = db.announcements.find((a) => a.id === variables.id);
      if (ann) {
        ann.status = "published";
        ann.publishedAt = Date.now();
        ann.updatedAt = Date.now();
        recordAudit("ANNOUNCEMENT_PUBLISH", "announcement", ann.id);
      }
      return HttpResponse.json({
        data: {
          publishAnnouncement: { id: variables.id, status: "published" },
        },
      });
    }

    // ── archiveAnnouncement ──
    if (operationName === "ArchiveAnnouncement") {
      const ann = db.announcements.find((a) => a.id === variables.id);
      if (ann) {
        ann.status = "archived";
        ann.updatedAt = Date.now();
        recordAudit("ANNOUNCEMENT_ARCHIVE", "announcement", ann.id);
      }
      return HttpResponse.json({
        data: { archiveAnnouncement: { id: variables.id, status: "archived" } },
      });
    }

    // ── toggleAnnouncementPin ──
    if (operationName === "ToggleAnnouncementPin") {
      const ann = db.announcements.find((a) => a.id === variables.id);
      if (ann) {
        ann.isPinned = !ann.isPinned;
        ann.updatedAt = Date.now();
      }
      return HttpResponse.json({
        data: {
          toggleAnnouncementPin: {
            id: variables.id,
            isPinned: ann?.isPinned ?? false,
          },
        },
      });
    }

    // ── adminInvitationCodes ──
    if (operationName === "AdminInvitationCodes") {
      return HttpResponse.json({
        data: {
          adminInvitationCodes: paginate(
            db.invitationCodes,
            variables.filter ?? {},
          ),
        },
      });
    }

    // ── generateInvitationCodes ──
    if (operationName === "GenerateInvitationCodes") {
      const input = variables.input;
      const count = Math.min(input.count ?? 10, 1000);
      const batchId = genId("bat");
      const charset = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
      const codes: string[] = [];
      for (let i = 0; i < count; i++) {
        let code = "";
        for (let j = 0; j < 8; j++) {
          code += charset[Math.floor(Math.random() * charset.length)];
        }
        codes.push(code);
        db.invitationCodes.unshift({
          id: genId("ic"),
          code,
          status: "unused",
          roleId: input.roleId ?? null,
          roleName: null,
          classId: input.classId ?? null,
          className: null,
          email: input.email ?? null,
          batchId,
          usedBy: null,
          usedByName: null,
          usedAt: null,
          createdAt: Date.now(),
          expiresAt: input.expiresAt ?? null,
        });
      }
      recordAudit("INVITATION_CODE_GENERATE", "invitation_code", batchId);
      return HttpResponse.json({
        data: { generateInvitationCodes: { codes, batchId } },
      });
    }

    // ── deleteInvitationCodes ──
    if (operationName === "DeleteInvitationCodes") {
      const ids = variables.ids as string[];
      db.invitationCodes = db.invitationCodes.filter(
        (ic) => !ids.includes(ic.id),
      );
      recordAudit("INVITATION_CODE_DELETE", "invitation_code", ids.join(","));
      return HttpResponse.json({ data: { deleteInvitationCodes: true } });
    }

    // ── adminFiles ──
    if (operationName === "AdminFiles") {
      return HttpResponse.json({
        data: { adminFiles: paginate(db.files, variables.filter ?? {}) },
      });
    }

    // ── adminFileStats ──
    if (operationName === "AdminFileStats") {
      return HttpResponse.json({ data: { adminFileStats: mockFileStats } });
    }

    // ── deleteFiles ──
    if (operationName === "DeleteFiles") {
      const ids = variables.ids as string[];
      db.files = db.files.filter((f) => !ids.includes(f.id));
      recordAudit("FILE_DELETE", "file", ids.join(","));
      return HttpResponse.json({ data: { deleteFiles: true } });
    }

    // ── aiProviders ──
    if (operationName === "AiProviders") {
      return HttpResponse.json({ data: { aiProviders: db.aiProviders } });
    }

    // ── updateAiProvider ──
    if (operationName === "UpdateAiProvider") {
      const provider = db.aiProviders.find((p) => p.id === variables.id);
      if (provider) {
        Object.assign(provider, variables.input);
      }
      return HttpResponse.json({
        data: {
          updateAiProvider: {
            id: variables.id,
            isActive: provider?.isActive ?? false,
          },
        },
      });
    }

    // ── aiUsage ──
    if (operationName === "AiUsage") {
      return HttpResponse.json({ data: { aiUsage: mockAiUsage } });
    }

    // ── 未匹配的 operation ──
    return HttpResponse.json(
      { errors: [{ message: `未实现的 GraphQL operation: ${operationName}` }] },
      { status: 501 },
    );
  }),
];
