import "server-only"

import { and, count, eq, gte, lte, sql } from "drizzle-orm"

import { db } from "@/shared/db"
import { attendanceRecords } from "@/shared/db/schema"
import {
  getClassActiveStudentsWithInfo,
  getClassNameById,
} from "@/modules/classes/data-access"
import { getGradeRecords } from "@/modules/grades/data-access"
import { safeParseDate } from "@/shared/lib/action-utils"
import type { DataScope } from "@/shared/types/permissions"

import { computeCorrelationSummary } from "./correlation-compute"
import type { AttendanceGradeCorrelationSummary } from "./types"

/**
 * L-9 考勤与成绩关联分析：跨模块数据访问层。
 *
 * 数据流：
 * 1. 通过 classes/data-access 获取班级学生列表
 * 2. 通过 attendance/data-access（本模块）SQL 聚合查询每个学生的出勤统计
 * 3. 通过 grades/data-access 获取该班级所有成绩记录，按学生聚合归一化平均分
 * 4. 调用纯函数 computeCorrelationSummary 计算相关系数和风险分级
 *
 * 跨模块通信严格遵循项目规则：通过对方 data-access 函数，不直接查询对方 DB 表。
 * 唯一例外是 attendance 模块自身的 attendanceRecords 表（本模块内查询）。
 *
 * 注意：gradeRecords 表查询通过 grades/data-access.getGradeRecords 完成。
 */

/** 默认时间范围：最近 90 天（无显式日期时使用）。 */
const DEFAULT_RANGE_DAYS = 90

/**
 * 获取班级考勤-成绩关联分析汇总。
 *
 * @param classId 班级 ID
 * @param startDate 起始日期（YYYY-MM-DD，可选）
 * @param endDate 结束日期（YYYY-MM-DD，可选）
 * @param scope 数据范围（用于权限校验）
 * @returns 关联分析汇总；班级不存在或无学生返回 null
 */
export async function getAttendanceGradeCorrelation(
  classId: string,
  startDate?: string,
  endDate?: string,
  scope?: DataScope
): Promise<AttendanceGradeCorrelationSummary | null> {
  // Step 1: 委托 classes data-access 获取班级名称与学生列表
  const className = await getClassNameById(classId)
  if (!className) return null

  // scope 校验：teacher scope 仅能查询自己任教的班级（class_taught）
  if (scope && scope.type === "class_taught") {
    if (!scope.classIds.includes(classId)) return null
  }
  // scope 校验：parent scope 仅能查询自己子女所在班级（class_members）
  // scope 校验：student scope（owned）不应访问班级级分析（返回 null）
  if (scope && scope.type === "owned") return null

  const students = await getClassActiveStudentsWithInfo(classId)
  if (students.length === 0) return null

  const studentIds = students.map((s) => s.id)
  const studentNameMap = new Map(students.map((s) => [s.id, s.name]))

  // 默认时间范围：最近 90 天
  const today = new Date()
  const effectiveEndDate = endDate ?? today.toISOString().slice(0, 10)
  const effectiveStartDate =
    startDate ??
    new Date(today.getTime() - DEFAULT_RANGE_DAYS * 24 * 60 * 60 * 1000)
      .toISOString()
      .slice(0, 10)

  // Step 2: 查询班级在时间范围内的考勤记录，按学生聚合
  // 复用 attendance 模块自身的 attendanceRecords 表（本模块内查询合规）
  const attendanceConditions = [
    eq(attendanceRecords.classId, classId),
    gte(attendanceRecords.date, safeParseDate(effectiveStartDate, "startDate")),
    lte(attendanceRecords.date, safeParseDate(effectiveEndDate, "endDate")),
  ]
  const attendanceWhere = and(...attendanceConditions)

  const attendanceRows = await db
    .select({
      studentId: attendanceRecords.studentId,
      total: count(),
      present: sql<number>`COALESCE(SUM(CASE WHEN ${attendanceRecords.status} = 'present' THEN 1 ELSE 0 END), 0)`,
      late: sql<number>`COALESCE(SUM(CASE WHEN ${attendanceRecords.status} = 'late' THEN 1 ELSE 0 END), 0)`,
      absent: sql<number>`COALESCE(SUM(CASE WHEN ${attendanceRecords.status} = 'absent' THEN 1 ELSE 0 END), 0)`,
      earlyLeave: sql<number>`COALESCE(SUM(CASE WHEN ${attendanceRecords.status} = 'early_leave' THEN 1 ELSE 0 END), 0)`,
    })
    .from(attendanceRecords)
    .where(attendanceWhere)
    .groupBy(attendanceRecords.studentId)

  const attendanceMap = new Map<
    string,
    {
      total: number
      present: number
      late: number
      absent: number
      earlyLeave: number
    }
  >()
  for (const r of attendanceRows) {
    attendanceMap.set(r.studentId, {
      total: Number(r.total),
      present: Number(r.present),
      late: Number(r.late),
      absent: Number(r.absent),
      earlyLeave: Number(r.earlyLeave),
    })
  }

  // Step 3: 委托 grades data-access 获取该班级所有成绩记录（按时间范围筛选 createdAt）
  // 注意：getGradeRecords 不直接支持 createdAt 范围筛选，因此这里传入 classId + scope
  // 后续在内存中按 createdAt 过滤时间范围（成绩数据量通常较小，可接受）
  const gradeResult = await getGradeRecords({
    classId,
    scope: scope ?? { type: "all" },
    limit: 5000,
  })

  // 内存中按时间范围过滤成绩记录（按 createdAt）
  const startTime = new Date(effectiveStartDate).getTime()
  const endTime = new Date(effectiveEndDate).getTime() + 24 * 60 * 60 * 1000 // 含结束日当天
  const filteredGradeRecords = gradeResult.records.filter((r) => {
    const createdAt = new Date(r.createdAt).getTime()
    return createdAt >= startTime && createdAt < endTime
  })

  // 按学生聚合成绩：归一化分数（score/fullScore*100）的加权平均（按 fullScore 加权）
  const gradeAggMap = new Map<
    string,
    { weightedSum: number; weightTotal: number; count: number }
  >()
  for (const r of filteredGradeRecords) {
    if (!studentIds.includes(r.studentId)) continue
    if (r.fullScore <= 0) continue // 跳过满分异常的记录
    const normalized = (r.score / r.fullScore) * 100
    const agg = gradeAggMap.get(r.studentId) ?? {
      weightedSum: 0,
      weightTotal: 0,
      count: 0,
    }
    agg.weightedSum += normalized * r.fullScore
    agg.weightTotal += r.fullScore
    agg.count += 1
    gradeAggMap.set(r.studentId, agg)
  }

  // Step 4: 合并考勤与成绩数据，构造原始数据点列表
  const rawItems = students.map((s) => {
    const attendance = attendanceMap.get(s.id)
    const grade = gradeAggMap.get(s.id)
    const total = attendance?.total ?? 0
    const present = attendance?.present ?? 0
    const late = attendance?.late ?? 0
    const absent = (attendance?.absent ?? 0) + (attendance?.earlyLeave ?? 0)
    // 出勤率：(present + late) / total * 100（late 视为出勤但迟到）
    const attendanceRate =
      total > 0 ? ((present + late) / total) * 100 : 0
    const averageScore =
      grade && grade.weightTotal > 0
        ? grade.weightedSum / grade.weightTotal
        : 0
    return {
      studentId: s.id,
      studentName: studentNameMap.get(s.id) ?? "Unknown",
      attendanceRate,
      attendanceRecordCount: total,
      absentCount: absent,
      averageScore,
      gradeRecordCount: grade?.count ?? 0,
    }
  })

  // Step 5: 调用纯函数计算相关系数与风险分级
  return computeCorrelationSummary(
    classId,
    className,
    effectiveStartDate,
    effectiveEndDate,
    rawItems
  )
}

/**
 * Scope 辅助：检查 scope 是否允许访问班级级关联分析。
 * 仅 all / class_taught（含该班级）/ grade_managed 允许；其余返回 false。
 */
export function canAccessCorrelationAnalysis(
  scope: DataScope,
  classId: string
): boolean {
  if (scope.type === "all") return true
  if (scope.type === "class_taught") return scope.classIds.includes(classId)
  if (scope.type === "grade_managed") return false // 暂不支持年级管理员跨班级分析
  return false // class_members / children / owned 不允许班级级分析
}
