"use server"

import { revalidatePath } from "next/cache"
import { createId } from "@paralleldrive/cuid2"
import { getTranslations } from "next-intl/server"

import { requirePermission, PermissionDeniedError } 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 { sendBatchNotifications } from "@/modules/notifications"
import type { NotificationPayload } from "@/modules/notifications"
import { getAllUserIds, getUserIdsByGradeId } from "@/modules/users/data-access"
import {
  getStudentIdsByClassId,
  getTeacherIdsByClassIds,
} from "@/modules/classes/data-access"

import { CreateAnnouncementSchema, UpdateAnnouncementSchema } from "./schema"
import {
  getAnnouncements,
  getAnnouncementById,
  insertAnnouncement,
  updateAnnouncementById,
  deleteAnnouncementById,
  publishAnnouncementById,
  archiveAnnouncementById,
  toggleAnnouncementPin,
  markAnnouncementAsRead,
  getAnnouncementReadStatusForUser,
} from "./data-access"
import type { GetAnnouncementsParams, Announcement } from "./types"

function handleActionError(e: unknown): ActionState<never> {
  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" }
}

/**
 * 根据公告类型解析目标用户 ID 列表。
 * - school: 全校所有用户
 * - grade: 该年级下所有用户
 * - class: 该班级学生 + 任课教师 + 班主任
 */
async function resolveTargetUserIds(announcement: Announcement): Promise<string[]> {
  if (announcement.type === "school") {
    return getAllUserIds()
  }

  if (announcement.type === "grade" && announcement.targetGradeId) {
    return getUserIdsByGradeId(announcement.targetGradeId)
  }

  if (announcement.type === "class" && announcement.targetClassId) {
    const [studentIds, teacherIds] = await Promise.all([
      getStudentIdsByClassId(announcement.targetClassId),
      getTeacherIdsByClassIds([announcement.targetClassId]),
    ])
    return Array.from(new Set([...studentIds, ...teacherIds]))
  }

  return []
}

/**
 * 发布公告后向目标用户批量发送通知。
 * 通知发送失败不影响公告发布本身，仅记录日志。
 */
async function notifyAnnouncementPublished(announcement: Announcement): Promise<void> {
  try {
    const targetUserIds = await resolveTargetUserIds(announcement)
    if (targetUserIds.length === 0) return

    const t = await getTranslations("announcements")
    const title = t("notification.publishedTitle", { title: announcement.title })
    const content = t("notification.publishedContent")

    const payloads: NotificationPayload[] = targetUserIds.map((userId) => ({
      userId,
      title,
      content,
      type: "info",
      actionUrl: `/announcements/${announcement.id}`,
      metadata: {
        announcementId: announcement.id,
        announcementType: announcement.type,
      },
    }))

    await sendBatchNotifications(payloads)
  } catch (error) {
    // 通知发送失败不阻塞公告发布流程，仅记录错误
    console.error("Failed to send announcement notifications:", error)
  }
}

export async function createAnnouncementAction(
  prevState: ActionState<string> | null,
  formData: FormData
): Promise<ActionState<string>> {
  try {
    const ctx = await requirePermission(Permissions.ANNOUNCEMENT_MANAGE)

    const parsed = CreateAnnouncementSchema.safeParse({
      title: formData.get("title"),
      content: formData.get("content"),
      type: formData.get("type") || undefined,
      status: formData.get("status") || undefined,
      targetGradeId: formData.get("targetGradeId") || undefined,
      targetClassId: formData.get("targetClassId") || undefined,
      publishedAt: formData.get("publishedAt") || undefined,
    })

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

    const input = parsed.data
    const isPublished = input.status === "published"
    const publishedAt = isPublished
      ? input.publishedAt
        ? new Date(input.publishedAt)
        : new Date()
      : input.publishedAt
        ? new Date(input.publishedAt)
        : null

    const id = await insertAnnouncement({
      id: createId(),
      title: input.title,
      content: input.content,
      type: input.type,
      status: input.status,
      targetGradeId: input.targetGradeId,
      targetClassId: input.targetClassId,
      authorId: ctx.userId,
      publishedAt,
    })

    // 如果创建时直接发布，触发通知（失败不阻塞）
    if (isPublished) {
      const created = await getAnnouncementById(id)
      if (created) {
        await notifyAnnouncementPublished(created)
      }
    }

    revalidatePath("/admin/announcements")
    revalidatePath("/announcements")

    void trackEvent({
      event: isPublished ? "announcement.published" : "announcement.created",
      userId: ctx.userId,
      targetId: id,
      targetType: "announcement",
      properties: { type: input.type, status: input.status },
    })

    return { success: true, message: "Announcement created", data: id }
  } catch (e) {
    return handleActionError(e)
  }
}

export async function updateAnnouncementAction(
  id: string,
  prevState: ActionState<string> | null,
  formData: FormData
): Promise<ActionState<string>> {
  try {
    await requirePermission(Permissions.ANNOUNCEMENT_MANAGE)

    const existing = await getAnnouncementById(id)
    if (!existing) return { success: false, message: "Announcement not found" }

    const parsed = UpdateAnnouncementSchema.safeParse({
      title: formData.get("title"),
      content: formData.get("content"),
      type: formData.get("type") || undefined,
      status: formData.get("status") || undefined,
      targetGradeId: formData.get("targetGradeId") || undefined,
      targetClassId: formData.get("targetClassId") || undefined,
      publishedAt: formData.get("publishedAt") || undefined,
    })

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

    const input = parsed.data
    const isPublished = input.status === "published"
    const wasPublished = existing.status === "published"
    const publishedAt = isPublished
      ? existing.publishedAt
        ? new Date(existing.publishedAt)
        : new Date()
      : input.publishedAt
        ? new Date(input.publishedAt)
        : null

    await updateAnnouncementById(id, {
      title: input.title,
      content: input.content,
      type: input.type,
      status: input.status,
      targetGradeId: input.targetGradeId,
      targetClassId: input.targetClassId,
      publishedAt,
      updatedAt: new Date(),
    })

    // 当公告从非发布状态变为发布状态时，触发通知（失败不阻塞）
    if (isPublished && !wasPublished) {
      const updated = await getAnnouncementById(id)
      if (updated) {
        await notifyAnnouncementPublished(updated)
      }
    }

    revalidatePath("/admin/announcements")
    revalidatePath(`/admin/announcements/${id}`)
    revalidatePath("/announcements")

    void trackEvent({
      event: isPublished && !wasPublished ? "announcement.published" : "announcement.updated",
      targetId: id,
      targetType: "announcement",
      properties: { type: input.type, status: input.status, wasPublished },
    })

    return { success: true, message: "Announcement updated", data: id }
  } catch (e) {
    return handleActionError(e)
  }
}

export async function deleteAnnouncementAction(id: string): Promise<ActionState<string>> {
  try {
    await requirePermission(Permissions.ANNOUNCEMENT_MANAGE)

    const existing = await getAnnouncementById(id)
    if (!existing) return { success: false, message: "Announcement not found" }

    await deleteAnnouncementById(id)

    revalidatePath("/admin/announcements")
    revalidatePath("/announcements")

    void trackEvent({
      event: "announcement.deleted",
      targetId: id,
      targetType: "announcement",
      properties: { type: existing.type, status: existing.status },
    })

    return { success: true, message: "Announcement deleted" }
  } catch (e) {
    return handleActionError(e)
  }
}

export async function publishAnnouncementAction(id: string): Promise<ActionState<string>> {
  try {
    await requirePermission(Permissions.ANNOUNCEMENT_MANAGE)

    const existing = await getAnnouncementById(id)
    if (!existing) return { success: false, message: "Announcement not found" }

    const publishedAt = existing.publishedAt
      ? new Date(existing.publishedAt)
      : new Date()
    await publishAnnouncementById(id, publishedAt)

    // 发布成功后触发通知（失败不阻塞）
    await notifyAnnouncementPublished(existing)

    revalidatePath("/admin/announcements")
    revalidatePath(`/admin/announcements/${id}`)
    revalidatePath("/announcements")

    void trackEvent({
      event: "announcement.published",
      targetId: id,
      targetType: "announcement",
      properties: { type: existing.type },
    })

    return { success: true, message: "Announcement published" }
  } catch (e) {
    return handleActionError(e)
  }
}

export async function archiveAnnouncementAction(id: string): Promise<ActionState<string>> {
  try {
    await requirePermission(Permissions.ANNOUNCEMENT_MANAGE)

    const existing = await getAnnouncementById(id)
    if (!existing) return { success: false, message: "Announcement not found" }

    await archiveAnnouncementById(id)

    revalidatePath("/admin/announcements")
    revalidatePath(`/admin/announcements/${id}`)
    revalidatePath("/announcements")

    void trackEvent({
      event: "announcement.archived",
      targetId: id,
      targetType: "announcement",
      properties: { type: existing.type },
    })

    return { success: true, message: "Announcement archived" }
  } catch (e) {
    return handleActionError(e)
  }
}

// ---------------------------------------------------------------------------
// V2-P2-13d: 公告置顶 Server Action
// ---------------------------------------------------------------------------

export async function toggleAnnouncementPinAction(id: string): Promise<ActionState<string>> {
  try {
    await requirePermission(Permissions.ANNOUNCEMENT_MANAGE)

    await toggleAnnouncementPin(id)
    revalidatePath("/admin/announcements")
    revalidatePath("/announcements")

    void trackEvent({
      event: "announcement.pin_toggled",
      targetId: id,
      targetType: "announcement",
    })

    return { success: true, message: "Pin status toggled" }
  } catch (e) {
    return handleActionError(e)
  }
}

// ---------------------------------------------------------------------------
// V2-P2-13d: 公告已读标记 Server Action
// ---------------------------------------------------------------------------

export async function markAnnouncementAsReadAction(announcementId: string): Promise<ActionState<string>> {
  try {
    const ctx = await requirePermission(Permissions.ANNOUNCEMENT_READ)

    await markAnnouncementAsRead(announcementId, ctx.userId)

    void trackEvent({
      event: "announcement.marked_read",
      userId: ctx.userId,
      targetId: announcementId,
      targetType: "announcement",
    })

    return { success: true, message: "Announcement marked as read" }
  } catch (e) {
    return handleActionError(e)
  }
}

/**
 * 批量获取公告已读状态（用于列表页标记已读/未读）。
 */
export async function getAnnouncementReadStatusAction(
  announcementIds: string[]
): Promise<ActionState<Record<string, boolean>>> {
  try {
    const ctx = await requirePermission(Permissions.ANNOUNCEMENT_READ)
    const statusMap = await getAnnouncementReadStatusForUser(announcementIds, ctx.userId)
    return { success: true, data: Object.fromEntries(statusMap) }
  } catch (e) {
    return handleActionError(e)
  }
}

export async function getAnnouncementsAction(
  params?: GetAnnouncementsParams
): Promise<ActionState<Announcement[]>> {
  try {
    await requirePermission(Permissions.ANNOUNCEMENT_READ)
    const data = await getAnnouncements(params)
    return { success: true, data }
  } catch (e) {
    return handleActionError(e)
  }
}
