import "server-only"

import { cache } from "react"
import { and, asc, desc, eq, inArray, or, sql } from "drizzle-orm"

import { db } from "@/shared/db"
import { academicYears, departments, grades, roles, schools, subjects, users, usersToRoles } from "@/shared/db/schema"
import type {
  AcademicYearInsertData,
  AcademicYearListItem,
  AcademicYearUpdateData,
  DepartmentInsertData,
  DepartmentListItem,
  DepartmentUpdateData,
  GradeInsertData,
  GradeListItem,
  GradeUpdateData,
  OrgTreeNode,
  SchoolInsertData,
  SchoolListItem,
  SchoolUpdateData,
  StaffOption,
} from "./types"

const toIso = (d: Date): string => d.toISOString()

export const getDepartments = cache(async (): Promise<DepartmentListItem[]> => {
  try {
    const rows = await db.select().from(departments).orderBy(asc(departments.name))
    return rows.map((r) => ({
      id: r.id,
      name: r.name,
      description: r.description ?? null,
      createdAt: toIso(r.createdAt),
      updatedAt: toIso(r.updatedAt),
    }))
  } catch (error) {
    console.error("getDepartments failed:", error)
    return []
  }
})

export const getAcademicYears = cache(async (): Promise<AcademicYearListItem[]> => {
  try {
    const rows = await db.select().from(academicYears).orderBy(asc(academicYears.startDate))
    return rows.map((r) => ({
      id: r.id,
      name: r.name,
      startDate: toIso(r.startDate),
      endDate: toIso(r.endDate),
      isActive: Boolean(r.isActive),
      createdAt: toIso(r.createdAt),
      updatedAt: toIso(r.updatedAt),
    }))
  } catch (error) {
    console.error("getAcademicYears failed:", error)
    return []
  }
})

export const getSchools = cache(async (): Promise<SchoolListItem[]> => {
  try {
    const rows = await db.select().from(schools).orderBy(asc(schools.name))
    return rows.map((r) => ({
      id: r.id,
      name: r.name,
      code: r.code ?? null,
      createdAt: toIso(r.createdAt),
      updatedAt: toIso(r.updatedAt),
    }))
  } catch (error) {
    console.error("getSchools failed:", error)
    return []
  }
})

export const getGrades = cache(async (): Promise<GradeListItem[]> => {
  try {
    const rows = await db
      .select({
        id: grades.id,
        name: grades.name,
        order: grades.order,
        schoolId: schools.id,
        schoolName: schools.name,
        gradeHeadId: grades.gradeHeadId,
        teachingHeadId: grades.teachingHeadId,
        createdAt: grades.createdAt,
        updatedAt: grades.updatedAt,
      })
      .from(grades)
      .innerJoin(schools, eq(schools.id, grades.schoolId))
      .orderBy(asc(schools.name), asc(grades.order), asc(grades.name))

    const headIds = Array.from(
      new Set(
        rows
          .flatMap((r) => [r.gradeHeadId, r.teachingHeadId])
          .filter((v): v is string => typeof v === "string" && v.length > 0)
      )
    )

    const heads = headIds.length
      ? await db
          .select({ id: users.id, name: users.name, email: users.email })
          .from(users)
          .where(inArray(users.id, headIds))
      : []

    const headById = new Map<string, StaffOption>()
    for (const u of heads) {
      headById.set(u.id, { id: u.id, name: u.name ?? "Unnamed", email: u.email })
    }

    return rows.map((r) => ({
      id: r.id,
      school: { id: r.schoolId, name: r.schoolName },
      name: r.name,
      order: Number(r.order ?? 0),
      gradeHead: r.gradeHeadId ? headById.get(r.gradeHeadId) ?? null : null,
      teachingHead: r.teachingHeadId ? headById.get(r.teachingHeadId) ?? null : null,
      createdAt: toIso(r.createdAt),
      updatedAt: toIso(r.updatedAt),
    }))
  } catch (error) {
    console.error("getGrades failed:", error)
    return []
  }
})

export const getStaffOptions = cache(async (): Promise<StaffOption[]> => {
  try {
    const rows = await db
      .select({ id: users.id, name: users.name, email: users.email })
      .from(users)
      .innerJoin(usersToRoles, eq(usersToRoles.userId, users.id))
      .innerJoin(roles, eq(usersToRoles.roleId, roles.id))
      .where(inArray(roles.name, ["teacher", "admin"]))
      .groupBy(users.id, users.name, users.email)
      .orderBy(asc(users.name), asc(users.email))

    return rows.map((r) => ({
      id: r.id,
      name: r.name ?? "Unnamed",
      email: r.email,
    }))
  } catch (error) {
    console.error("getStaffOptions failed:", error)
    return []
  }
})

export const getGradesForStaff = cache(async (staffId: string): Promise<GradeListItem[]> => {
  const id = staffId.trim()
  if (!id) return []

  try {
    const rows = await db
      .select({
        id: grades.id,
        name: grades.name,
        order: grades.order,
        schoolId: schools.id,
        schoolName: schools.name,
        gradeHeadId: grades.gradeHeadId,
        teachingHeadId: grades.teachingHeadId,
        createdAt: grades.createdAt,
        updatedAt: grades.updatedAt,
      })
      .from(grades)
      .innerJoin(schools, eq(schools.id, grades.schoolId))
      .where(or(eq(grades.gradeHeadId, id), eq(grades.teachingHeadId, id)))
      .orderBy(asc(schools.name), asc(grades.order), asc(grades.name))

    const headIds = Array.from(
      new Set(
        rows
          .flatMap((r) => [r.gradeHeadId, r.teachingHeadId])
          .filter((v): v is string => typeof v === "string" && v.length > 0)
      )
    )

    const heads = headIds.length
      ? await db
          .select({ id: users.id, name: users.name, email: users.email })
          .from(users)
          .where(inArray(users.id, headIds))
      : []

    const headById = new Map<string, StaffOption>()
    for (const u of heads) headById.set(u.id, { id: u.id, name: u.name ?? "Unnamed", email: u.email })

    return rows.map((r) => ({
      id: r.id,
      school: { id: r.schoolId, name: r.schoolName },
      name: r.name,
      order: Number(r.order ?? 0),
      gradeHead: r.gradeHeadId ? headById.get(r.gradeHeadId) ?? null : null,
      teachingHead: r.teachingHeadId ? headById.get(r.teachingHeadId) ?? null : null,
      createdAt: toIso(r.createdAt),
      updatedAt: toIso(r.updatedAt),
    }))
  } catch (error) {
    console.error("getGradesForStaff failed:", error)
    return []
  }
})

/**
 * 根据用户角色返回可见的学校列表（权限感知）。
 * - admin: 返回全量学校
 * - grade_head / teaching_head: 返回其负责年级所在学校
 * - teacher: 返回其任课班级所在学校
 * - 其他角色: 返回空数组
 */
export const getSchoolsForUser = cache(async (userId: string): Promise<SchoolListItem[]> => {
  const id = userId.trim()
  if (!id) return []

  try {
    const roleRows = await db
      .select({ name: roles.name })
      .from(roles)
      .innerJoin(usersToRoles, eq(usersToRoles.roleId, roles.id))
      .where(eq(usersToRoles.userId, id))

    const roleNames = new Set(roleRows.map((r) => r.name))

    if (roleNames.has("admin")) {
      return await getSchools()
    }

    let schoolIds: string[] = []

    if (roleNames.has("grade_head") || roleNames.has("teaching_head")) {
      const gradeRows = await db
        .select({ schoolId: grades.schoolId })
        .from(grades)
        .where(or(eq(grades.gradeHeadId, id), eq(grades.teachingHeadId, id)))
      schoolIds = gradeRows.map((r) => r.schoolId)
    } else if (roleNames.has("teacher")) {
      const { getAccessibleClassIdsForTeacher, getGradeIdsByClassIds } = await import("@/modules/classes/data-access")
      const classIds = await getAccessibleClassIdsForTeacher(id)
      if (classIds.length === 0) return []

      const gradeIds = await getGradeIdsByClassIds(classIds)
      if (gradeIds.length === 0) return []

      const gradeRows = await db
        .select({ schoolId: grades.schoolId })
        .from(grades)
        .where(inArray(grades.id, gradeIds))
      schoolIds = gradeRows.map((r) => r.schoolId)
    } else {
      return []
    }

    const uniqueSchoolIds = Array.from(
      new Set(schoolIds.filter((v): v is string => typeof v === "string" && v.length > 0))
    )
    if (uniqueSchoolIds.length === 0) return []

    const rows = await db
      .select()
      .from(schools)
      .where(inArray(schools.id, uniqueSchoolIds))
      .orderBy(asc(schools.name))

    return rows.map((r) => ({
      id: r.id,
      name: r.name,
      code: r.code ?? null,
      createdAt: toIso(r.createdAt),
      updatedAt: toIso(r.updatedAt),
    }))
  } catch (error) {
    console.error("getSchoolsForUser failed:", error)
    return []
  }
})

/**
 * 根据用户角色返回可见的年级列表（权限感知）。
 * - admin: 返回全量年级
 * - grade_head / teaching_head: 返回其负责的年级
 * - teacher: 返回其任课班级所在年级
 * - 其他角色: 返回空数组
 */
export const getGradesForUser = cache(async (userId: string): Promise<GradeListItem[]> => {
  const id = userId.trim()
  if (!id) return []

  try {
    const roleRows = await db
      .select({ name: roles.name })
      .from(roles)
      .innerJoin(usersToRoles, eq(usersToRoles.roleId, roles.id))
      .where(eq(usersToRoles.userId, id))

    const roleNames = new Set(roleRows.map((r) => r.name))

    if (roleNames.has("admin")) {
      return await getGrades()
    }

    if (roleNames.has("grade_head") || roleNames.has("teaching_head")) {
      return await getGradesForStaff(id)
    }

    if (roleNames.has("teacher")) {
      const { getAccessibleClassIdsForTeacher, getGradeIdsByClassIds } = await import("@/modules/classes/data-access")
      const classIds = await getAccessibleClassIdsForTeacher(id)
      if (classIds.length === 0) return []

      const gradeIds = await getGradeIdsByClassIds(classIds)
      if (gradeIds.length === 0) return []

      const uniqueGradeIds = Array.from(new Set(gradeIds))
      if (uniqueGradeIds.length === 0) return []

      const rows = await db
        .select({
          id: grades.id,
          name: grades.name,
          order: grades.order,
          schoolId: schools.id,
          schoolName: schools.name,
          gradeHeadId: grades.gradeHeadId,
          teachingHeadId: grades.teachingHeadId,
          createdAt: grades.createdAt,
          updatedAt: grades.updatedAt,
        })
        .from(grades)
        .innerJoin(schools, eq(schools.id, grades.schoolId))
        .where(inArray(grades.id, uniqueGradeIds))
        .orderBy(asc(schools.name), asc(grades.order), asc(grades.name))

      const headIds = Array.from(
        new Set(
          rows
            .flatMap((r) => [r.gradeHeadId, r.teachingHeadId])
            .filter((v): v is string => typeof v === "string" && v.length > 0)
        )
      )

      const heads = headIds.length
        ? await db
            .select({ id: users.id, name: users.name, email: users.email })
            .from(users)
            .where(inArray(users.id, headIds))
        : []

      const headById = new Map<string, StaffOption>()
      for (const u of heads) headById.set(u.id, { id: u.id, name: u.name ?? "Unnamed", email: u.email })

      return rows.map((r) => ({
        id: r.id,
        school: { id: r.schoolId, name: r.schoolName },
        name: r.name,
        order: Number(r.order ?? 0),
        gradeHead: r.gradeHeadId ? headById.get(r.gradeHeadId) ?? null : null,
        teachingHead: r.teachingHeadId ? headById.get(r.teachingHeadId) ?? null : null,
        createdAt: toIso(r.createdAt),
        updatedAt: toIso(r.updatedAt),
      }))
    }

    return []
  } catch (error) {
    console.error("getGradesForUser failed:", error)
    return []
  }
})

// ---------------------------------------------------------------------------
// Mutations — DB write operations (called only from actions.ts)
// ---------------------------------------------------------------------------

export async function createDepartment(data: DepartmentInsertData): Promise<void> {
  await db.insert(departments).values({
    id: data.id,
    name: data.name,
    description: data.description,
  })
}

export async function updateDepartment(
  id: string,
  data: DepartmentUpdateData
): Promise<void> {
  await db
    .update(departments)
    .set({ name: data.name, description: data.description })
    .where(eq(departments.id, id))
}

export async function deleteDepartment(id: string): Promise<void> {
  await db.delete(departments).where(eq(departments.id, id))
}

export async function createSchool(data: SchoolInsertData): Promise<void> {
  await db.insert(schools).values({
    id: data.id,
    name: data.name,
    code: data.code,
  })
}

export async function updateSchool(
  id: string,
  data: SchoolUpdateData
): Promise<void> {
  await db
    .update(schools)
    .set({ name: data.name, code: data.code })
    .where(eq(schools.id, id))
}

export async function deleteSchool(id: string): Promise<void> {
  await db.delete(schools).where(eq(schools.id, id))
}

export async function createGrade(data: GradeInsertData): Promise<void> {
  await db.insert(grades).values({
    id: data.id,
    schoolId: data.schoolId,
    name: data.name,
    order: data.order,
    gradeHeadId: data.gradeHeadId,
    teachingHeadId: data.teachingHeadId,
  })
}

export async function updateGrade(
  id: string,
  data: GradeUpdateData
): Promise<void> {
  await db
    .update(grades)
    .set({
      schoolId: data.schoolId,
      name: data.name,
      order: data.order,
      gradeHeadId: data.gradeHeadId,
      teachingHeadId: data.teachingHeadId,
    })
    .where(eq(grades.id, id))
}

export async function deleteGrade(id: string): Promise<void> {
  await db.delete(grades).where(eq(grades.id, id))
}

export async function createAcademicYear(
  data: AcademicYearInsertData
): Promise<void> {
  await db.transaction(async (tx) => {
    if (data.isActive) {
      await tx.update(academicYears).set({ isActive: false })
    }
    await tx.insert(academicYears).values({
      id: data.id,
      name: data.name,
      startDate: data.startDate,
      endDate: data.endDate,
      isActive: data.isActive,
    })
  })
}

export async function updateAcademicYear(
  id: string,
  data: AcademicYearUpdateData
): Promise<void> {
  await db.transaction(async (tx) => {
    if (data.isActive) {
      await tx.update(academicYears).set({ isActive: false })
    }
    await tx
      .update(academicYears)
      .set({
        name: data.name,
        startDate: data.startDate,
        endDate: data.endDate,
        isActive: data.isActive,
      })
      .where(eq(academicYears.id, id))
  })
}

export async function deleteAcademicYear(id: string): Promise<void> {
  await db.delete(academicYears).where(eq(academicYears.id, id))
}

// ---------------------------------------------------------------------------
// Cross-module query interfaces — read-only access for other modules
// ---------------------------------------------------------------------------

export type SubjectOption = {
  id: string
  name: string
  code: string | null
  order: number
}

export type GradeOption = {
  id: string
  name: string
  schoolId: string
  schoolName: string
  order: number
}

export const getSubjectOptions = cache(async (): Promise<SubjectOption[]> => {
  try {
    const rows = await db
      .select({
        id: subjects.id,
        name: subjects.name,
        code: subjects.code,
        order: subjects.order,
      })
      .from(subjects)
      .orderBy(asc(subjects.order), asc(subjects.name))

    return rows.map((r) => ({
      id: r.id,
      name: r.name,
      code: r.code ?? null,
      order: Number(r.order ?? 0),
    }))
  } catch (error) {
    console.error("getSubjectOptions failed:", error)
    return []
  }
})

export const getGradeOptions = cache(async (): Promise<GradeOption[]> => {
  try {
    const rows = await db
      .select({
        id: grades.id,
        name: grades.name,
        order: grades.order,
        schoolId: schools.id,
        schoolName: schools.name,
      })
      .from(grades)
      .innerJoin(schools, eq(schools.id, grades.schoolId))
      .orderBy(asc(schools.name), asc(grades.order), asc(grades.name))

    return rows.map((r) => ({
      id: r.id,
      name: r.name,
      schoolId: r.schoolId,
      schoolName: r.schoolName,
      order: Number(r.order ?? 0),
    }))
  } catch (error) {
    console.error("getGradeOptions failed:", error)
    return []
  }
})

/**
 * 按 ID 获取单个年级名称。
 * 供跨模块调用使用，避免为单个年级拉取全量年级选项。
 */
export const getGradeNameById = cache(
  async (gradeId: string): Promise<string | null> => {
    const id = gradeId.trim()
    if (!id) return null
    const [row] = await db
      .select({ name: grades.name })
      .from(grades)
      .where(eq(grades.id, id))
      .limit(1)
    return row?.name ?? null
  },
)

/**
 * 按 ID 获取单个科目名称。
 * 供跨模块调用使用，避免为单个科目拉取全量科目选项或直接查询 subjects 表。
 */
export const getSubjectNameById = cache(
  async (subjectId: string): Promise<string | null> => {
    const id = subjectId.trim()
    if (!id) return null
    const [row] = await db
      .select({ name: subjects.name })
      .from(subjects)
      .where(eq(subjects.id, id))
      .limit(1)
    return row?.name ?? null
  },
)

/**
 * 批量获取科目名称映射（subjectId -> name）。
 * 供跨模块调用使用，避免直接查询 subjects 表。
 */
export const getSubjectNameMapByIds = cache(
  async (subjectIds: string[]): Promise<Map<string, string | null>> => {
    const ids = subjectIds.filter((id) => id.trim().length > 0)
    if (ids.length === 0) return new Map()
    const rows = await db
      .select({ id: subjects.id, name: subjects.name })
      .from(subjects)
      .where(inArray(subjects.id, ids))
    const map = new Map<string, string | null>()
    for (const r of rows) map.set(r.id, r.name)
    return map
  },
)

// ---------------------------------------------------------------------------
// Cross-module query interfaces — grade head/teaching head verification
// ---------------------------------------------------------------------------

/**
 * 校验用户是否为指定年级的年级主任。
 * 供 classes 模块跨模块调用使用，避免直接查询 grades 表。
 */
export const isGradeHead = cache(async (
  gradeId: string,
  userId: string
): Promise<boolean> => {
  const trimmedGradeId = gradeId.trim()
  const trimmedUserId = userId.trim()
  if (!trimmedGradeId || !trimmedUserId) return false

  const [row] = await db
    .select({ id: grades.id })
    .from(grades)
    .where(and(eq(grades.id, trimmedGradeId), eq(grades.gradeHeadId, trimmedUserId)))
    .limit(1)
  return Boolean(row)
})

/**
 * 校验用户是否为指定年级的年级主任或教学主任。
 * 供 classes 模块跨模块调用使用，避免直接查询 grades 表。
 */
export const isGradeManager = cache(async (
  gradeId: string,
  userId: string
): Promise<boolean> => {
  const trimmedGradeId = gradeId.trim()
  const trimmedUserId = userId.trim()
  if (!trimmedGradeId || !trimmedUserId) return false

  const [row] = await db
    .select({ id: grades.id })
    .from(grades)
    .where(
      and(
        eq(grades.id, trimmedGradeId),
        or(eq(grades.gradeHeadId, trimmedUserId), eq(grades.teachingHeadId, trimmedUserId))
      )
    )
    .limit(1)
  return Boolean(row)
})

/**
 * 根据年级名称（大小写不敏感）查找用户担任年级主任的年级 ID。
 * 供 classes 模块跨模块调用使用，避免直接查询 grades 表。
 */
export const findGradeIdByHeadAndName = cache(async (
  userId: string,
  gradeName: string
): Promise<string | null> => {
  const trimmedUserId = userId.trim()
  const normalizedGradeName = gradeName.trim().toLowerCase()
  if (!trimmedUserId || !normalizedGradeName) return null

  const [row] = await db
    .select({ id: grades.id })
    .from(grades)
    .where(
      and(
        eq(grades.gradeHeadId, trimmedUserId),
        sql`LOWER(${grades.name}) = ${normalizedGradeName}`
      )
    )
    .limit(1)
  return row?.id ?? null
})

/**
 * 将年级名称升级：一年级→二年级，1年级→2年级，Grade 1→Grade 2
 * 无法识别的名称保持不变。
 */
function promoteGradeName(name: string): string {
  // 中文数字映射
  const chineseNums = ["一", "二", "三", "四", "五", "六", "七", "八", "九", "十", "十一", "十二"]
  for (let i = 0; i < chineseNums.length - 1; i++) {
    if (name.includes(chineseNums[i]) && !name.includes(chineseNums[i + 1])) {
      return name.replace(chineseNums[i], chineseNums[i + 1])
    }
  }

  // 阿拉伯数字
  const match = name.match(/(\d+)/)
  if (match) {
    const num = parseInt(match[1], 10)
    if (num > 0 && num < 13) {
      return name.replace(match[1], String(num + 1))
    }
  }

  return name
}

/**
 * 年级升级：将指定学校下的所有年级 order +1，并更新年级名称（如果符合数字模式）。
 * 例如：一年级 → 二年级，order 1 → 2
 *
 * 注意：此函数只更新年级本身的 order 和 name，不迁移班级数据。
 * 班级升级应由 classes 模块的独立 Action 处理。
 */
export async function promoteGrades(schoolId: string): Promise<{ promoted: number }> {
  const rows = await db
    .select({ id: grades.id, name: grades.name, order: grades.order })
    .from(grades)
    .where(eq(grades.schoolId, schoolId))
    .orderBy(desc(grades.order)) // 从高到低升级，避免唯一约束冲突

  let promoted = 0
  for (const row of rows) {
    const newOrder = (row.order ?? 0) + 1
    const newName = promoteGradeName(row.name)
    await db
      .update(grades)
      .set({ order: newOrder, name: newName })
      .where(eq(grades.id, row.id))
    promoted += 1
  }

  return { promoted }
}

/**
 * 获取学校→年级→班级三级组织架构树。
 * 班级数据通过 classes 模块的 data-access 动态导入获取，避免循环依赖。
 * 任何一层查询失败均返回空数组，保证调用方拿到稳定结构。
 */
export const getOrgTree = cache(async (): Promise<OrgTreeNode[]> => {
  try {
    const [schoolList, gradeList] = await Promise.all([getSchools(), getGrades()])

    const { getAdminClasses } = await import("@/modules/classes/data-access")
    const allClasses = await getAdminClasses()

    const classesByGradeId = new Map<string, OrgTreeNode[]>()
    for (const cls of allClasses) {
      const gradeId = cls.gradeId
      if (typeof gradeId !== "string" || gradeId.length === 0) continue
      const node: OrgTreeNode = {
        id: cls.id,
        name: cls.name,
        type: "class",
      }
      const list = classesByGradeId.get(gradeId)
      if (list) {
        list.push(node)
      } else {
        classesByGradeId.set(gradeId, [node])
      }
    }

    const gradesBySchoolId = new Map<string, OrgTreeNode[]>()
    for (const grade of gradeList) {
      const children = classesByGradeId.get(grade.id) ?? []
      const node: OrgTreeNode = {
        id: grade.id,
        name: grade.name,
        type: "grade",
        children,
      }
      const list = gradesBySchoolId.get(grade.school.id)
      if (list) {
        list.push(node)
      } else {
        gradesBySchoolId.set(grade.school.id, [node])
      }
    }

    return schoolList.map((school) => ({
      id: school.id,
      name: school.name,
      type: "school",
      children: gradesBySchoolId.get(school.id) ?? [],
    }))
  } catch (error) {
    console.error("getOrgTree failed:", error)
    return []
  }
})

/**
 * 年级概览统计：每个年级的班级数、学生数、教师数。
 * 用于年级管理页面的卡片视图，让管理员一目了然看到各年级规模。
 */
export interface GradeOverviewStats {
  gradeId: string
  classCount: number
  studentCount: number
  teacherCount: number
}

export const getGradeOverviewStats = cache(async (): Promise<GradeOverviewStats[]> => {
  try {
    // 动态导入 classes 模块避免循环依赖
    const { getAdminClasses } = await import("@/modules/classes/data-access")
    const allClasses = await getAdminClasses()

    // 按年级分组统计班级数和学生数
    const statsByGrade = new Map<string, { classCount: number; studentCount: number; teacherIds: Set<string> }>()

    for (const cls of allClasses) {
      const gradeId = cls.gradeId
      if (typeof gradeId !== "string" || gradeId.length === 0) continue

      const existing = statsByGrade.get(gradeId) ?? { classCount: 0, studentCount: 0, teacherIds: new Set<string>() }
      existing.classCount += 1
      existing.studentCount += cls.studentCount ?? 0
      // 班主任算一个教师
      if (cls.teacher?.id) existing.teacherIds.add(cls.teacher.id)
      // 学科教师也算
      for (const st of cls.subjectTeachers ?? []) {
        if (st.teacher?.id) existing.teacherIds.add(st.teacher.id)
      }
      statsByGrade.set(gradeId, existing)
    }

    return Array.from(statsByGrade.entries()).map(([gradeId, s]) => ({
      gradeId,
      classCount: s.classCount,
      studentCount: s.studentCount,
      teacherCount: s.teacherIds.size,
    }))
  } catch (error) {
    console.error("getGradeOverviewStats failed:", error)
    return []
  }
})
