import "server-only"

import { sendBatchNotifications } from "@/modules/notifications"
import { getParentStudentMapByStudentIds } from "@/modules/parent/data-access"
import { getUserNamesByIds } from "@/modules/users/data-access"
import { getClassNameById } from "@/modules/classes/data-access"

import type { AttendanceStatus } from "./types"

/**
 * L-2：触发家长缺勤通知的状态集合。
 * 缺勤/迟到/早退/请假 需要通知家长；出勤/校内活动 不通知。
 */
const NOTIFIABLE_STATUSES: ReadonlySet<AttendanceStatus> = new Set([
  "absent",
  "late",
  "early_leave",
  "excused",
])

/**
 * L-2：考勤记录输入（用于通知）。
 */
interface AttendanceNotificationInput {
  studentId: string
  status: AttendanceStatus
  date: string
  reason?: string | null
}

/**
 * L-2：对缺勤/异常考勤记录批量发送家长通知。
 *
 * 通知策略：
 * - 仅对 NOTIFIABLE_STATUSES 中的状态发送通知
 * - 一次性批量查询学生→家长映射，避免 N+1
 * - 调用 notifications 模块的 sendBatchNotifications 多渠道分发
 * - 通知失败不阻断考勤记录保存（仅记录日志）
 *
 * @param classId 班级 ID（用于通知内容）
 * @param records 考勤记录列表
 * @returns 发送结果（成功/失败计数）
 */
export async function notifyParentsOfAbsence(
  classId: string,
  records: AttendanceNotificationInput[],
): Promise<{ sent: number; failed: number; skipped: number }> {
  // 过滤需要通知的记录
  const notifiable = records.filter((r) => NOTIFIABLE_STATUSES.has(r.status))
  if (notifiable.length === 0) {
    return { sent: 0, failed: 0, skipped: records.length }
  }

  // 一次性批量查询所有受影响学生的家长映射（保留 parentId-studentId 关联）
  const studentIds = notifiable.map((r) => r.studentId)
  const parentStudentPairs = await getParentStudentMapByStudentIds(studentIds)
  if (parentStudentPairs.length === 0) {
    return { sent: 0, failed: 0, skipped: records.length }
  }

  // 并行查询班级名称和学生姓名
  const [className, studentNameMap] = await Promise.all([
    getClassNameById(classId),
    getUserNamesByIds(studentIds),
  ])

  // 构造按学生索引的记录映射（同一学生一天可能只一条记录，但保险起见用 Map）
  const recordByStudent = new Map<string, AttendanceNotificationInput>()
  for (const r of notifiable) {
    recordByStudent.set(r.studentId, r)
  }

  // 构造通知负载：每个家长-学生组合一条通知
  const notificationPayloads = parentStudentPairs
    .map((pair) => {
      const record = recordByStudent.get(pair.studentId)
      if (!record) return null
      const studentName = studentNameMap.get(pair.studentId)?.name ?? "Unknown"
      return {
        userId: pair.parentId,
        title: `考勤提醒：${studentName} ${statusLabel(record.status)}`,
        content: buildNotificationContent(
          studentName,
          record.status,
          record.date,
          record.reason ?? null,
          className ?? "",
        ),
        type: "warning" as const,
        metadata: {
          module: "attendance",
          studentId: pair.studentId,
          classId,
          status: record.status,
          date: record.date,
        },
        actionUrl: "/parent/attendance",
      }
    })
    .filter((p): p is NonNullable<typeof p> => p !== null)

  if (notificationPayloads.length === 0) {
    return { sent: 0, failed: 0, skipped: records.length - notifiable.length }
  }

  try {
    const results = await sendBatchNotifications(notificationPayloads)
    let sent = 0
    let failed = 0
    for (const channelResults of results) {
      const hasSuccess = channelResults.some((r) => r.success)
      if (hasSuccess) {
        sent += 1
      } else {
        failed += 1
      }
    }
    return { sent, failed, skipped: records.length - notifiable.length }
  } catch {
    // 通知发送失败不阻断主流程
    return {
      sent: 0,
      failed: notificationPayloads.length,
      skipped: records.length - notifiable.length,
    }
  }
}

/** 状态中文标签（通知内容用，不走 i18n 因通知在服务端发送且无请求上下文）。 */
function statusLabel(status: AttendanceStatus): string {
  const labels: Record<AttendanceStatus, string> = {
    present: "出勤",
    absent: "缺勤",
    late: "迟到",
    early_leave: "早退",
    excused: "请假",
    school_activity: "校内活动",
  }
  return labels[status] ?? status
}

/** 构造通知正文。 */
function buildNotificationContent(
  studentName: string,
  status: AttendanceStatus,
  date: string,
  reason: string | null,
  className: string,
): string {
  const statusText = statusLabel(status)
  const classInfo = className ? `${className} ` : ""
  const reasonInfo = reason ? `（原因：${reason}）` : ""
  return `${classInfo}${studentName} 同学于 ${date} 被标记为「${statusText}」${reasonInfo}，请关注子女考勤情况。`
}
