"use server"

/**
 * 通知 Server Actions
 *
 * - sendNotificationAction: 发送通知给指定用户（需要 MESSAGE_SEND 权限）
 * - sendClassNotificationAction: 发送班级通知（教师权限，按班级查询学生后批量发送）
 * - getNotificationsAction / markNotificationAsReadAction / markAllNotificationsAsReadAction / getUnreadNotificationCountAction: 站内通知 CRUD
 *
 * 权限说明:
 * 项目无独立 NOTIFICATION_SEND 权限点，复用 MESSAGE_SEND（教师/管理员/年级主任均拥有）。
 * 班级通知按教师所教班级过滤，确保教师只能给自己班级发通知。
 * 站内通知读取/标记已读复用 MESSAGE_READ 权限（任何能读消息的用户都能查看通知）。
 */

import { revalidatePath } from "next/cache"
import { z } from "zod"
import { PermissionDeniedError, requirePermission } from "@/shared/lib/auth-guard"
import { trackEvent } from "@/shared/lib/track-event"
import { Permissions } from "@/shared/types/permissions"
import type { ActionState } from "@/shared/types/action-state"

import { getClassExists, getStudentIdsByClassId } from "@/modules/classes/data-access"

import { sendNotification, sendBatchNotifications } from "./dispatcher"
import {
  getNotifications,
  markNotificationAsRead,
  markAllNotificationsAsRead,
  getUnreadNotificationCount,
  archiveNotification,
} from "./data-access"
import {
  getNotificationPreferences,
  upsertNotificationPreferences,
} from "./preferences"
import { UpdateNotificationPreferencesSchema } from "./schema"
import type { NotificationPayload, ChannelSendResult, Notification, NotificationPreferences, UpdateNotificationPreferencesInput } from "./types"

/**
 * Zod 校验：通知负载（sendNotificationAction 入参）
 * 校验 userId / title / content 必填，type 限定为枚举值
 */
const SendNotificationSchema = z.object({
  userId: z.string().trim().min(1),
  title: z.string().trim().min(1).max(255),
  content: z.string().trim().min(1),
  type: z.enum(["info", "warning", "error", "success"]),
  metadata: z.record(z.string(), z.unknown()).optional(),
  actionUrl: z.string().trim().max(500).optional(),
})

/**
 * Zod 校验：班级通知负载（sendClassNotificationAction 入参）
 * 与 SendNotificationSchema 类似，但不含 userId（由班级学生列表填充）
 */
const SendClassNotificationSchema = z.object({
  title: z.string().trim().min(1).max(255),
  content: z.string().trim().min(1),
  type: z.enum(["info", "warning", "error", "success"]),
  metadata: z.record(z.string(), z.unknown()).optional(),
  actionUrl: z.string().trim().max(500).optional(),
})

/** Zod 校验：classId 路径参数 */
const ClassIdSchema = z.string().trim().min(1)

/**
 * 发送通知给指定用户。
 *
 * @param payload 通知负载（payload.userId 为接收人）
 */
export async function sendNotificationAction(
  payload: NotificationPayload
): Promise<ActionState<ChannelSendResult[]>> {
  try {
    await requirePermission(Permissions.MESSAGE_SEND)

    const parsed = SendNotificationSchema.safeParse(payload)
    if (!parsed.success) {
      return {
        success: false,
        message: "Invalid payload",
        errors: parsed.error.flatten().fieldErrors,
      }
    }

    const results = await sendNotification(parsed.data)
    const allSuccess = results.every((r) => r.success)
    return {
      success: allSuccess,
      message: allSuccess ? "Notification sent" : "Some channels failed",
      data: results,
    }
  } catch (e) {
    if (e instanceof PermissionDeniedError) return { success: false, message: e.message }
    if (e instanceof Error) return { success: false, message: e.message }
    return { success: false, message: "Unexpected error" }
  }
}

/**
 * 发送班级通知（批量发送给班级所有学生）。
 *
 * 教师只能给自己所教班级发送通知（通过 dataScope 校验）。
 *
 * @param classId 班级 ID
 * @param payload 通知负载模板（payload.userId 会被覆盖为每个学生的 userId）
 */
export async function sendClassNotificationAction(
  classId: string,
  payload: Omit<NotificationPayload, "userId">
): Promise<ActionState<ChannelSendResult[][]>> {
  try {
    const ctx = await requirePermission(Permissions.MESSAGE_SEND)

    const parsedClassId = ClassIdSchema.safeParse(classId)
    const parsedPayload = SendClassNotificationSchema.safeParse(payload)
    if (!parsedClassId.success || !parsedPayload.success) {
      const errors: Record<string, string[]> = {}
      if (!parsedClassId.success) {
        errors.classId = parsedClassId.error.flatten().formErrors
      }
      if (!parsedPayload.success) {
        Object.assign(errors, parsedPayload.error.flatten().fieldErrors)
      }
      return {
        success: false,
        message: "Invalid input",
        errors,
      }
    }

    const validClassId = parsedClassId.data

    // 权限校验: 教师只能给自己所教班级发通知；管理员可发任意班级
    if (ctx.dataScope.type !== "all") {
      const allowedClassIds =
        ctx.dataScope.type === "class_taught" ? ctx.dataScope.classIds : []
      if (!allowedClassIds.includes(validClassId)) {
        return { success: false, message: "You can only send notifications to your own classes" }
      }
    }

    // 校验班级是否存在
    const classExists = await getClassExists(validClassId)
    if (!classExists) {
      return { success: false, message: "Class not found" }
    }

    // 查询班级所有学生
    const studentIds = await getStudentIdsByClassId(validClassId)

    if (studentIds.length === 0) {
      return { success: true, message: "No students in this class", data: [] }
    }

    // 构造每个学生的通知负载
    const payloads: NotificationPayload[] = studentIds.map((studentId) => ({
      ...parsedPayload.data,
      userId: studentId,
    }))

    const results = await sendBatchNotifications(payloads)
    return {
      success: true,
      message: `Notification sent to ${studentIds.length} students`,
      data: results,
    }
  } catch (e) {
    if (e instanceof PermissionDeniedError) return { success: false, message: e.message }
    if (e instanceof Error) return { success: false, message: e.message }
    return { success: false, message: "Unexpected error" }
  }
}

// ---------------------------------------------------------------------------
// 站内通知 CRUD Server Actions
//
// 这些 Action 从 messaging/actions.ts 迁移而来，使 notifications 模块成为
// 通知相关 UI 组件的唯一数据来源，消除 messaging 与 notifications 在 UI 层
// 的双向耦合。权限复用 MESSAGE_READ（任何能读消息的用户都能查看通知）。
// ---------------------------------------------------------------------------

/** Zod 校验：通知 ID 路径参数 */
const NotificationIdSchema = z.string().trim().min(1)

/**
 * 获取当前用户的通知列表（分页）。
 */
export async function getNotificationsAction(
  params?: { page?: number; pageSize?: number; unreadOnly?: boolean }
): Promise<ActionState<{ items: Notification[]; total: number; page: number; pageSize: number; totalPages: number }>> {
  try {
    const ctx = await requirePermission(Permissions.MESSAGE_READ)
    const result = await getNotifications(ctx.userId, params)
    return { success: true, data: result }
  } catch (e) {
    if (e instanceof PermissionDeniedError) return { success: false, message: e.message }
    if (e instanceof Error) return { success: false, message: e.message }
    return { success: false, message: "Unexpected error" }
  }
}

/**
 * 获取当前用户的未读通知计数。
 */
export async function getUnreadNotificationCountAction(): Promise<ActionState<number>> {
  try {
    const ctx = await requirePermission(Permissions.MESSAGE_READ)
    const count = await getUnreadNotificationCount(ctx.userId)
    return { success: true, data: count }
  } catch (e) {
    if (e instanceof PermissionDeniedError) return { success: false, message: e.message }
    if (e instanceof Error) return { success: false, message: e.message }
    return { success: false, message: "Unexpected error" }
  }
}

/**
 * 将单条通知标记为已读。
 */
export async function markNotificationAsReadAction(
  notificationId: string
): Promise<ActionState<string>> {
  try {
    const ctx = await requirePermission(Permissions.MESSAGE_READ)

    const parsed = NotificationIdSchema.safeParse(notificationId)
    if (!parsed.success) {
      return { success: false, message: "Invalid notification id" }
    }

    await markNotificationAsRead(parsed.data, ctx.userId)
    revalidatePath("/messages")

    void trackEvent({
      event: "notification.marked_read",
      userId: ctx.userId,
      targetId: parsed.data,
      targetType: "notification",
    })

    return { success: true, message: "Notification marked as read" }
  } catch (e) {
    if (e instanceof PermissionDeniedError) return { success: false, message: e.message }
    if (e instanceof Error) return { success: false, message: e.message }
    return { success: false, message: "Unexpected error" }
  }
}

/**
 * 将当前用户的所有未读通知标记为已读。
 */
export async function markAllNotificationsAsReadAction(): Promise<ActionState<string>> {
  try {
    const ctx = await requirePermission(Permissions.MESSAGE_READ)
    await markAllNotificationsAsRead(ctx.userId)
    revalidatePath("/messages")

    void trackEvent({
      event: "notification.marked_all_read",
      userId: ctx.userId,
      targetType: "notification",
    })

    return { success: true, message: "All notifications marked as read" }
  } catch (e) {
    if (e instanceof PermissionDeniedError) return { success: false, message: e.message }
    if (e instanceof Error) return { success: false, message: e.message }
    return { success: false, message: "Unexpected error" }
  }
}

/**
 * 将单条通知归档（归档后不在默认列表显示）。
 */
export async function archiveNotificationAction(
  notificationId: string
): Promise<ActionState<string>> {
  try {
    const ctx = await requirePermission(Permissions.MESSAGE_READ)

    const parsed = NotificationIdSchema.safeParse(notificationId)
    if (!parsed.success) {
      return { success: false, message: "Invalid notification id" }
    }

    await archiveNotification(parsed.data, ctx.userId)
    revalidatePath("/messages")

    void trackEvent({
      event: "notification.archived",
      userId: ctx.userId,
      targetId: parsed.data,
      targetType: "notification",
    })

    return { success: true, message: "Notification archived" }
  } catch (e) {
    if (e instanceof PermissionDeniedError) return { success: false, message: e.message }
    if (e instanceof Error) return { success: false, message: e.message }
    return { success: false, message: "Unexpected error" }
  }
}

// ---------------------------------------------------------------------------
// 通知偏好 Server Actions
//
// V3-P1-3: 从 messaging/actions.ts 迁移至 notifications/actions.ts，
// 使通知偏好的 data-access、schema、actions 位于同一模块。
// 权限复用 MESSAGE_READ（任何能读消息的用户都能管理通知偏好）。
// ---------------------------------------------------------------------------

/**
 * 获取当前用户的通知偏好。
 */
export async function getNotificationPreferencesAction(): Promise<ActionState<NotificationPreferences>> {
  try {
    const ctx = await requirePermission(Permissions.MESSAGE_READ)
    const prefs = await getNotificationPreferences(ctx.userId)
    return { success: true, data: prefs }
  } catch (e) {
    if (e instanceof PermissionDeniedError) return { success: false, message: e.message }
    if (e instanceof Error) return { success: false, message: e.message }
    return { success: false, message: "Unexpected error" }
  }
}

/**
 * 更新当前用户的通知偏好。
 *
 * 从 FormData 中解析布尔值（checkbox 提交 "on" 或不提交）和时间字符串。
 */
export async function updateNotificationPreferencesAction(
  prevState: ActionState<NotificationPreferences> | null,
  formData: FormData
): Promise<ActionState<NotificationPreferences>> {
  try {
    const ctx = await requirePermission(Permissions.MESSAGE_READ)

    const parseBool = (key: string): boolean => formData.get(key) === "on"
    const parseTime = (key: string): string | null => {
      const v = formData.get(key)
      if (typeof v !== "string") return null
      const trimmed = v.trim()
      return trimmed.length > 0 ? trimmed : null
    }

    const parsed = UpdateNotificationPreferencesSchema.safeParse({
      emailEnabled: parseBool("emailEnabled"),
      smsEnabled: parseBool("smsEnabled"),
      pushEnabled: parseBool("pushEnabled"),
      homeworkNotifications: parseBool("homeworkNotifications"),
      gradeNotifications: parseBool("gradeNotifications"),
      announcementNotifications: parseBool("announcementNotifications"),
      messageNotifications: parseBool("messageNotifications"),
      attendanceNotifications: parseBool("attendanceNotifications"),
      quietHoursEnabled: parseBool("quietHoursEnabled"),
      quietHoursStart: parseTime("quietHoursStart"),
      quietHoursEnd: parseTime("quietHoursEnd"),
    })

    if (!parsed.success) {
      return { success: false, message: "Invalid form data", errors: parsed.error.flatten().fieldErrors }
    }

    const input: UpdateNotificationPreferencesInput = parsed.data

    const updated = await upsertNotificationPreferences(ctx.userId, input)
    if (!updated) {
      return { success: false, message: "Failed to update notification preferences" }
    }

    revalidatePath("/settings")

    return { success: true, message: "Notification preferences updated", data: updated }
  } catch (e) {
    if (e instanceof PermissionDeniedError) return { success: false, message: e.message }
    if (e instanceof Error) return { success: false, message: e.message }
    return { success: false, message: "Unexpected error" }
  }
}
