import "server-only";

import { cache } from "react"
import { and, asc, eq, inArray, type SQL } from "drizzle-orm"

import { db } from "@/shared/db"
import {
  classes,
  classEnrollments,
  classSchedule,
} from "@/shared/db/schema"
import type {
  ClassScheduleItem,
  StudentScheduleItem,
} from "./types"
import {
  getAccessibleClassIdsForTeacher,
  getSessionTeacherId,
} from "./data-access"

/**
 * 根据课表项 ID 获取其所属班级 ID（P0-3 审计修复：供 actions-schedule 越权校验使用）。
 * classes 模块对 classSchedule 表有读权限（usedBy 含 classes）。
 */
export async function getClassIdByScheduleId(scheduleId: string): Promise<string | null> {
  const [row] = await db
    .select({ classId: classSchedule.classId })
    .from(classSchedule)
    .where(eq(classSchedule.id, scheduleId))
    .limit(1)
  return row?.classId ?? null
}

const isWeekday = (n: unknown): n is 1 | 2 | 3 | 4 | 5 | 6 | 7 =>
  typeof n === "number" && n >= 1 && n <= 7 && Number.isInteger(n)

const toWeekday = (n: number): 1 | 2 | 3 | 4 | 5 | 6 | 7 =>
  isWeekday(n) ? n : 1

export const getStudentSchedule = cache(async (studentId: string): Promise<StudentScheduleItem[]> => {
  const id = studentId.trim()
  if (!id) return []

  const rows = await db
    .select({
      id: classSchedule.id,
      classId: classSchedule.classId,
      className: classes.name,
      weekday: classSchedule.weekday,
      startTime: classSchedule.startTime,
      endTime: classSchedule.endTime,
      course: classSchedule.course,
      location: classSchedule.location,
    })
    .from(classEnrollments)
    .innerJoin(classes, eq(classes.id, classEnrollments.classId))
    .innerJoin(classSchedule, eq(classSchedule.classId, classes.id))
    .where(and(eq(classEnrollments.studentId, id), eq(classEnrollments.status, "active")))
    .orderBy(asc(classSchedule.weekday), asc(classSchedule.startTime))

  return rows.map((r) => ({
    id: r.id,
    classId: r.classId,
    className: r.className,
    weekday: toWeekday(r.weekday),
    startTime: r.startTime,
    endTime: r.endTime,
    course: r.course,
    location: r.location,
  }))
})

export const getClassSchedule = cache(
  async (params?: { classId?: string; teacherId?: string }): Promise<ClassScheduleItem[]> => {
    const teacherId = params?.teacherId ?? (await getSessionTeacherId())
    if (!teacherId) return []

    const classId = params?.classId?.trim()

    const accessibleIds = await getAccessibleClassIdsForTeacher(teacherId)
    if (accessibleIds.length === 0) return []

    const conditions: SQL[] = [inArray(classes.id, accessibleIds)]
    if (classId) conditions.push(eq(classSchedule.classId, classId))

    const rows = await db
      .select({
        id: classSchedule.id,
        classId: classSchedule.classId,
        weekday: classSchedule.weekday,
        startTime: classSchedule.startTime,
        endTime: classSchedule.endTime,
        course: classSchedule.course,
        location: classSchedule.location,
      })
      .from(classSchedule)
      .innerJoin(classes, eq(classes.id, classSchedule.classId))
      .where(and(...conditions))
      .orderBy(asc(classSchedule.weekday), asc(classSchedule.startTime))

    return rows.map((r) => ({
      id: r.id,
      classId: r.classId,
      weekday: toWeekday(r.weekday),
      startTime: r.startTime,
      endTime: r.endTime,
      course: r.course,
      location: r.location,
    }))
  }
)
