import "server-only"

/**
 * 通知偏好数据访问层
 *
 * 职责:
 * - getNotificationPreferences: 获取用户通知偏好（无记录时自动创建默认记录）
 * - upsertNotificationPreferences: 更新或创建用户通知偏好
 *
 * 表所有权: notification_preferences（由 notifications 模块统一管理）
 *
 * 注意: 本文件从 messaging/notification-preferences.ts 迁移而来，
 * 消除 notifications -> messaging 的反向依赖（P0-4 / P1-5 修复）。
 */

import { cache } from "react"
import { createId } from "@paralleldrive/cuid2"
import { and, eq } from "drizzle-orm"

import { db } from "@/shared/db"
import { notificationPreferences } from "@/shared/db/schema"
import type {
  NotificationPreferences,
  UpdateNotificationPreferencesInput,
} from "./types"

const toIso = (d: Date): string => d.toISOString()

const mapRow = (
  row: typeof notificationPreferences.$inferSelect
): NotificationPreferences => ({
  id: row.id,
  userId: row.userId,
  emailEnabled: row.emailEnabled,
  smsEnabled: row.smsEnabled,
  pushEnabled: row.pushEnabled,
  homeworkNotifications: row.homeworkNotifications,
  gradeNotifications: row.gradeNotifications,
  announcementNotifications: row.announcementNotifications,
  messageNotifications: row.messageNotifications,
  attendanceNotifications: row.attendanceNotifications,
  quietHoursEnabled: row.quietHoursEnabled,
  quietHoursStart: row.quietHoursStart,
  quietHoursEnd: row.quietHoursEnd,
  createdAt: toIso(row.createdAt),
  updatedAt: toIso(row.updatedAt),
})

// 默认偏好值（首次创建时使用）
const DEFAULTS = {
  emailEnabled: false,
  smsEnabled: false,
  pushEnabled: true,
  homeworkNotifications: true,
  gradeNotifications: true,
  announcementNotifications: true,
  messageNotifications: true,
  attendanceNotifications: true,
  quietHoursEnabled: false,
  quietHoursStart: null,
  quietHoursEnd: null,
}

/**
 * 获取用户的通知偏好设置
 * 如果用户尚无记录，则自动创建一条默认记录并返回
 */
export const getNotificationPreferences = cache(
  async (userId: string): Promise<NotificationPreferences> => {
    // 先查询
    const [existing] = await db
      .select()
      .from(notificationPreferences)
      .where(eq(notificationPreferences.userId, userId))
      .limit(1)

    if (existing) {
      return mapRow(existing)
    }

    // 不存在则创建默认记录
    const id = createId()
    try {
      await db.insert(notificationPreferences).values({
        id,
        userId,
        ...DEFAULTS,
      })
      const [created] = await db
        .select()
        .from(notificationPreferences)
        .where(eq(notificationPreferences.id, id))
        .limit(1)
      if (created) return mapRow(created)
    } catch {
      // 并发情况下可能违反唯一约束，回退到查询
      const [fallback] = await db
        .select()
        .from(notificationPreferences)
        .where(eq(notificationPreferences.userId, userId))
        .limit(1)
      if (fallback) return mapRow(fallback)
    }

    // 极端情况：返回内存中的默认值（不带 id）
    return {
      id: "",
      userId,
      ...DEFAULTS,
      createdAt: toIso(new Date()),
      updatedAt: toIso(new Date()),
    }
  }
)

/**
 * 更新（或创建）用户的通知偏好设置
 * 使用 upsert 语义：存在则更新，不存在则插入
 */
export async function upsertNotificationPreferences(
  userId: string,
  input: UpdateNotificationPreferencesInput
): Promise<NotificationPreferences | null> {
  // 先查询是否存在
  const [existing] = await db
    .select()
    .from(notificationPreferences)
    .where(eq(notificationPreferences.userId, userId))
    .limit(1)

  if (existing) {
    // 更新
    const updateData: Partial<typeof notificationPreferences.$inferInsert> = {}
    if (input.emailEnabled !== undefined) updateData.emailEnabled = input.emailEnabled
    if (input.smsEnabled !== undefined) updateData.smsEnabled = input.smsEnabled
    if (input.pushEnabled !== undefined) updateData.pushEnabled = input.pushEnabled
    if (input.homeworkNotifications !== undefined) updateData.homeworkNotifications = input.homeworkNotifications
    if (input.gradeNotifications !== undefined) updateData.gradeNotifications = input.gradeNotifications
    if (input.announcementNotifications !== undefined) updateData.announcementNotifications = input.announcementNotifications
    if (input.messageNotifications !== undefined) updateData.messageNotifications = input.messageNotifications
    if (input.attendanceNotifications !== undefined) updateData.attendanceNotifications = input.attendanceNotifications
    if (input.quietHoursEnabled !== undefined) updateData.quietHoursEnabled = input.quietHoursEnabled
    if (input.quietHoursStart !== undefined) updateData.quietHoursStart = input.quietHoursStart
    if (input.quietHoursEnd !== undefined) updateData.quietHoursEnd = input.quietHoursEnd

    if (Object.keys(updateData).length === 0) {
      return mapRow(existing)
    }

    await db
      .update(notificationPreferences)
      .set(updateData)
      .where(and(eq(notificationPreferences.id, existing.id), eq(notificationPreferences.userId, userId)))

    const [updated] = await db
      .select()
      .from(notificationPreferences)
      .where(eq(notificationPreferences.id, existing.id))
      .limit(1)
    return updated ? mapRow(updated) : null
  }

  // 不存在则插入
  const id = createId()
  try {
    await db.insert(notificationPreferences).values({
      id,
      userId,
      emailEnabled: input.emailEnabled ?? DEFAULTS.emailEnabled,
      smsEnabled: input.smsEnabled ?? DEFAULTS.smsEnabled,
      pushEnabled: input.pushEnabled ?? DEFAULTS.pushEnabled,
      homeworkNotifications: input.homeworkNotifications ?? DEFAULTS.homeworkNotifications,
      gradeNotifications: input.gradeNotifications ?? DEFAULTS.gradeNotifications,
      announcementNotifications: input.announcementNotifications ?? DEFAULTS.announcementNotifications,
      messageNotifications: input.messageNotifications ?? DEFAULTS.messageNotifications,
      attendanceNotifications: input.attendanceNotifications ?? DEFAULTS.attendanceNotifications,
      quietHoursEnabled: input.quietHoursEnabled ?? DEFAULTS.quietHoursEnabled,
      quietHoursStart: input.quietHoursStart ?? DEFAULTS.quietHoursStart,
      quietHoursEnd: input.quietHoursEnd ?? DEFAULTS.quietHoursEnd,
    })

    const [created] = await db
      .select()
      .from(notificationPreferences)
      .where(eq(notificationPreferences.id, id))
      .limit(1)
    return created ? mapRow(created) : null
  } catch {
    return null
  }
}
