"use server"

import { revalidatePath } from "next/cache"
import { getTranslations } from "next-intl/server"
import { requirePermission } from "@/shared/lib/auth-guard"
import { Permissions } from "@/shared/types/permissions"
import type { ActionState } from "@/shared/types/action-state"
import { handleActionError, safeJsonParse } from "@/shared/lib/action-utils"
import { trackEvent } from "@/shared/lib/track-event"
import { verifyTeacherOwnsClass } from "@/modules/classes/data-access"

import {
  RecordAttendanceSchema,
  BatchRecordAttendanceSchema,
  UpdateAttendanceSchema,
  AttendanceRuleSchema,
} from "./schema"
import {
  createAttendanceRecord,
  batchCreateAttendanceRecords,
  updateAttendanceRecord,
  deleteAttendanceRecord,
  getAttendanceRecordClassId,
  upsertAttendanceRules,
} from "./data-access"
import { notifyParentsOfAbsence } from "./notifications"

/**
 * 校验当前用户对考勤记录的归属权限。
 * - admin（scope=all）：直接放行
 * - teacher（scope=class_taught）：必须为记录所属班级的任课教师
 * - 其他 scope：拒绝（学生/家长不应调用写操作）
 */
async function assertRecordOwnership(
  recordId: string,
  ctx: Awaited<ReturnType<typeof requirePermission>>
): Promise<{ ok: boolean; message?: string }> {
  const t = await getTranslations("attendance")
  if (ctx.dataScope.type === "all") return { ok: true }
  if (ctx.dataScope.type === "class_taught") {
    const classId = await getAttendanceRecordClassId(recordId)
    if (!classId) return { ok: false, message: t("errors.notFound") }
    const owns = await verifyTeacherOwnsClass(classId, ctx.userId)
    if (!owns) return { ok: false, message: t("errors.noOwnership") }
    return { ok: true }
  }
  return { ok: false, message: t("errors.insufficientPermissions") }
}

/**
 * 校验当前用户对班级的归属权限。
 * - admin（scope=all）：直接放行
 * - teacher（scope=class_taught）：必须为该班级的任课教师
 * - 其他 scope：拒绝
 */
async function assertClassOwnership(
  classId: string,
  ctx: Awaited<ReturnType<typeof requirePermission>>
): Promise<{ ok: boolean; message?: string }> {
  const t = await getTranslations("attendance")
  if (ctx.dataScope.type === "all") return { ok: true }
  if (ctx.dataScope.type === "class_taught") {
    const owns = await verifyTeacherOwnsClass(classId, ctx.userId)
    if (!owns) return { ok: false, message: t("errors.noClassOwnership") }
    return { ok: true }
  }
  return { ok: false, message: t("errors.insufficientPermissions") }
}

export async function recordAttendanceAction(
  prevState: ActionState<string> | null,
  formData: FormData
): Promise<ActionState<string>> {
  try {
    const t = await getTranslations("attendance")
    const ctx = await requirePermission(Permissions.ATTENDANCE_MANAGE)

    const parsed = RecordAttendanceSchema.safeParse({
      studentId: formData.get("studentId"),
      classId: formData.get("classId"),
      date: formData.get("date"),
      status: formData.get("status"),
      // L-6：节次考勤，未传时由 Zod schema default("full_day") 兜底
      period: formData.get("period") || undefined,
      remark: formData.get("remark") || undefined,
      scheduleId: formData.get("scheduleId") || undefined,
    })

    if (!parsed.success) {
      return {
        success: false,
        message: t("errors.invalidForm"),
        errors: parsed.error.flatten().fieldErrors,
      }
    }

    const id = await createAttendanceRecord(parsed.data, ctx.userId)
    revalidatePath("/teacher/attendance")
    await trackEvent({
      event: "attendance.recorded",
      userId: ctx.userId,
      targetId: id,
      targetType: "attendance_record",
      properties: { studentId: parsed.data.studentId, classId: parsed.data.classId, status: parsed.data.status },
    })
    return { success: true, message: t("messages.recorded"), data: id }
  } catch (e) {
    return handleActionError(e)
  }
}

export async function batchRecordAttendanceAction(
  prevState: ActionState<number> | null,
  formData: FormData
): Promise<ActionState<number>> {
  try {
    const t = await getTranslations("attendance")
    const ctx = await requirePermission(Permissions.ATTENDANCE_MANAGE)

    const recordsJson = formData.get("recordsJson")
    if (typeof recordsJson !== "string" || recordsJson.length === 0) {
      return { success: false, message: t("errors.missingRecords") }
    }

    const parsed = BatchRecordAttendanceSchema.safeParse({
      records: safeJsonParse(recordsJson, t("errors.invalidRecordsJson")),
    })

    if (!parsed.success) {
      return {
        success: false,
        message: t("errors.invalidForm"),
        errors: parsed.error.flatten().fieldErrors,
      }
    }

    const count = await batchCreateAttendanceRecords(parsed.data, ctx.userId)
    revalidatePath("/teacher/attendance")
    await trackEvent({
      event: "attendance.batch_recorded",
      userId: ctx.userId,
      targetType: "attendance_record",
      properties: { count, classId: parsed.data.records[0]?.classId },
    })

    // L-2: 考勤记录保存成功后，异步通知家长（失败不阻断主流程）
    const classId = parsed.data.records[0]?.classId
    if (classId) {
      await notifyParentsOfAbsence(
        classId,
        parsed.data.records.map((r) => ({
          studentId: r.studentId,
          status: r.status,
          date: r.date,
          reason: r.reason ?? null,
        })),
      ).catch(() => {
        // 通知失败已被 notifyParentsOfAbsence 内部捕获，此处兜底防止未预期异常影响主流程
      })
    }

    return { success: true, message: t("messages.batchRecorded", { count }), data: count }
  } catch (e) {
    return handleActionError(e)
  }
}

export async function updateAttendanceAction(
  id: string,
  prevState: ActionState<string> | null,
  formData: FormData
): Promise<ActionState<string>> {
  try {
    const t = await getTranslations("attendance")
    const ctx = await requirePermission(Permissions.ATTENDANCE_MANAGE)

    const ownership = await assertRecordOwnership(id, ctx)
    if (!ownership.ok) {
      return { success: false, message: ownership.message ?? t("messages.ownershipCheckFailed") }
    }

    const parsed = UpdateAttendanceSchema.safeParse({
      status: formData.get("status") || undefined,
      // L-6：节次考勤，支持更新节次
      period: formData.get("period") || undefined,
      remark: formData.get("remark") || undefined,
      scheduleId: formData.get("scheduleId") || undefined,
    })

    if (!parsed.success) {
      return {
        success: false,
        message: t("errors.invalidForm"),
        errors: parsed.error.flatten().fieldErrors,
      }
    }

    await updateAttendanceRecord(id, parsed.data)
    revalidatePath("/teacher/attendance")
    await trackEvent({
      event: "attendance.updated",
      userId: ctx.userId,
      targetId: id,
      targetType: "attendance_record",
      properties: { status: parsed.data.status },
    })
    return { success: true, message: t("messages.updated") }
  } catch (e) {
    return handleActionError(e)
  }
}

export async function deleteAttendanceAction(
  id: string
): Promise<ActionState<string>> {
  try {
    const t = await getTranslations("attendance")
    const ctx = await requirePermission(Permissions.ATTENDANCE_MANAGE)

    const ownership = await assertRecordOwnership(id, ctx)
    if (!ownership.ok) {
      return { success: false, message: ownership.message ?? t("messages.ownershipCheckFailed") }
    }

    await deleteAttendanceRecord(id)
    revalidatePath("/teacher/attendance")
    await trackEvent({
      event: "attendance.deleted",
      userId: ctx.userId,
      targetId: id,
      targetType: "attendance_record",
    })
    return { success: true, message: t("messages.deleted") }
  } catch (e) {
    return handleActionError(e)
  }
}

export async function saveAttendanceRulesAction(
  prevState: ActionState<string> | null,
  formData: FormData
): Promise<ActionState<string>> {
  try {
    const t = await getTranslations("attendance")
    const ctx = await requirePermission(Permissions.ATTENDANCE_MANAGE)

    const parsed = AttendanceRuleSchema.safeParse({
      classId: formData.get("classId"),
      lateThresholdMinutes: formData.get("lateThresholdMinutes") || undefined,
      earlyLeaveThresholdMinutes: formData.get("earlyLeaveThresholdMinutes") || undefined,
      enableAutoMark: formData.get("enableAutoMark") === "true",
    })

    if (!parsed.success) {
      return {
        success: false,
        message: t("errors.invalidForm"),
        errors: parsed.error.flatten().fieldErrors,
      }
    }

    const ownership = await assertClassOwnership(parsed.data.classId, ctx)
    if (!ownership.ok) {
      return { success: false, message: ownership.message ?? t("messages.ownershipCheckFailed") }
    }

    const id = await upsertAttendanceRules(parsed.data)
    revalidatePath("/teacher/attendance")
    await trackEvent({
      event: "attendance.rules_saved",
      userId: ctx.userId,
      targetId: id,
      targetType: "attendance_rule",
      properties: { classId: parsed.data.classId },
    })
    return { success: true, message: t("messages.rulesSaved"), data: id }
  } catch (e) {
    return handleActionError(e)
  }
}
