import "server-only"

/**
 * 通知分发器
 *
 * 职责:
 * - 根据用户通知偏好（notification_preferences）决定使用哪些渠道
 * - 并行发送到多个渠道（in_app 总是启用）
 * - 记录每个渠道的发送结果到日志
 *
 * 渠道选择逻辑:
 * - in_app: 总是启用（pushEnabled 控制是否发送站内推送）
 * - sms: smsEnabled && 用户有手机号
 * - email: emailEnabled && 用户有邮箱
 * - wechat: pushEnabled && 用户有 wechatOpenId（当前 users 表无此字段，暂不发送）
 *
 * 注意: 通知偏好中的 homeworkNotifications/gradeNotifications 等是按通知类别控制，
 * 由调用方在构造 payload 时决定是否调用 sendNotification。
 */

import type { NotificationPayload, ChannelSendResult, NotificationChannel } from "./types"
import type { NotificationChannelSender, ChannelRecipient } from "./channels/types"
import { createSmsSender } from "./channels/sms-channel"
import { createWechatSender } from "./channels/wechat-channel"
import { createEmailSender } from "./channels/email-channel"
import { createInAppSender } from "./channels/in-app-channel"
import {
  getUserContactInfo,
  logNotificationSendBatch,
} from "./data-access"
import { getNotificationPreferences } from "./preferences"

/** 渠道发送器实例缓存（避免每次发送重新创建） */
interface SenderRegistry {
  in_app: NotificationChannelSender
  sms: NotificationChannelSender
  wechat: NotificationChannelSender
  email: NotificationChannelSender
}

let senderRegistry: SenderRegistry | null = null

/** 获取渠道发送器注册表（单例） */
function getSenders(): SenderRegistry {
  if (!senderRegistry) {
    senderRegistry = {
      in_app: createInAppSender(),
      sms: createSmsSender(),
      wechat: createWechatSender(),
      email: createEmailSender(),
    }
  }
  return senderRegistry
}

/**
 * 根据用户通知偏好和联系方式，决定启用的渠道列表。
 */
function selectChannels(
  prefs: {
    smsEnabled: boolean
    emailEnabled: boolean
    pushEnabled: boolean
  },
  contact: ChannelRecipient
): NotificationChannel[] {
  const channels: NotificationChannel[] = []

  // 站内消息总是启用（pushEnabled 控制站内推送，默认 true）
  if (prefs.pushEnabled) {
    channels.push("in_app")
  }

  // SMS: 偏好启用且有手机号
  if (prefs.smsEnabled && contact.phone) {
    channels.push("sms")
  }

  // Email: 偏好启用且有邮箱
  if (prefs.emailEnabled && contact.email) {
    channels.push("email")
  }

  // WeChat: 偏好启用且有 openId（当前 users 表无此字段，暂不会触发）
  if (prefs.pushEnabled && contact.wechatOpenId) {
    channels.push("wechat")
  }

  // 兜底: 如果所有渠道都未启用，至少发站内消息
  if (channels.length === 0) {
    channels.push("in_app")
  }

  return channels
}

/**
 * 发送单条通知到用户。
 *
 * 根据用户通知偏好选择渠道，并行发送，返回所有渠道的发送结果。
 *
 * @param payload 通知负载（payload.userId 决定接收人）
 * @returns 各渠道的发送结果
 */
export async function sendNotification(
  payload: NotificationPayload
): Promise<ChannelSendResult[]> {
  const userId = payload.userId

  // 并行获取用户偏好和联系方式
  const [prefs, contact] = await Promise.all([
    getNotificationPreferences(userId),
    getUserContactInfo(userId),
  ])

  const channels = selectChannels(prefs, contact)
  const senders = getSenders()

  // 并行发送到所有选中渠道
  const results = await Promise.all(
    channels.map((ch) => {
      const sender = senders[ch]
      return sender.send(payload, contact)
    })
  )

  // 记录发送日志（传入 payload 用于持久化）
  await logNotificationSendBatch(results, { userId: payload.userId, title: payload.title })

  return results
}

/**
 * 批量发送通知到多个用户。
 *
 * 每个用户的渠道选择独立计算，并行发送。
 *
 * @param payloads 通知负载数组（每个 payload.userId 决定各自接收人）
 * @returns 各用户各渠道的发送结果（按输入顺序对应）
 */
export async function sendBatchNotifications(
  payloads: NotificationPayload[]
): Promise<ChannelSendResult[][]> {
  // 并行处理每个 payload（每条通知的日志已在 sendNotification 内部记录）
  return Promise.all(payloads.map((p) => sendNotification(p)))
}
