import "server-only"

/**
 * 站内消息渠道
 *
 * 封装 notifications 模块的 data-access.createNotification，
 * 将其适配为统一的 NotificationChannelSender 接口。
 *
 * 这是默认渠道，总是启用。所有通知都会写入 message_notifications 表，
 * 用户可在站内通知中心查看。
 *
 * 注意: NotificationType 为 "message" | "announcement" | "homework" | "grade"，
 * 而本模块 NotificationPayload.type 为 "info" | "warning" | "error" | "success"。
 * 通过 mapPayloadTypeToNotificationType 函数进行语义映射（P0-11 修复），
 * 不再使用非法的 as 断言。
 *
 * P0-4 / P1-5 修复后，createNotification 已迁移到 notifications/data-access.ts，
 * 不再需要动态 import messaging 模块，消除了 notifications -> messaging 的反向依赖。
 */

import { createNotification } from "../data-access"
import type {
  NotificationPayload,
  ChannelSendResult,
  NotificationChannel,
} from "../types"
import type { NotificationChannelSender, ChannelRecipient } from "./types"

const channel: NotificationChannel = "in_app"

/**
 * Map NotificationPayload.type (info/warning/error/success) to
 * NotificationType (message/announcement/homework/grade).
 *
 * Since the DB column is varchar(128) and accepts any string,
 * we map by semantic meaning. "info" maps to "message" as the default
 * in-app notification category.
 */
function mapPayloadTypeToNotificationType(
  payloadType: NotificationPayload["type"]
): "message" | "announcement" | "homework" | "grade" {
  // Map by semantic meaning: info/success -> message (general),
  // warning -> announcement (needs attention), error -> grade (alert-like),
  // fallback to message. This is a reasonable default mapping.
  switch (payloadType) {
    case "info":
    case "success":
      return "message"
    case "warning":
      return "announcement"
    case "error":
      return "grade"
    default:
      return "message"
  }
}

/** 站内消息发送器（直接调用 notifications data-access） */
class InAppChannelSender implements NotificationChannelSender {
  readonly channel = channel

  async send(
    payload: NotificationPayload,
    recipient: ChannelRecipient
  ): Promise<ChannelSendResult> {
    try {
      // 校验收件人一致，防止误发
      if (recipient.userId !== payload.userId) {
        return {
          channel,
          success: false,
          error: "Recipient userId does not match payload.userId",
          sentAt: new Date(),
        }
      }
      const id = await createNotification({
        userId: payload.userId,
        // Map payload.type to NotificationType via type-safe mapping (P0-11)
        type: mapPayloadTypeToNotificationType(payload.type),
        title: payload.title,
        content: payload.content,
        link: payload.actionUrl ?? null,
      })
      return {
        channel,
        success: true,
        messageId: id,
        sentAt: new Date(),
      }
    } catch (e) {
      return {
        channel,
        success: false,
        error: e instanceof Error ? e.message : "In-app notification failed",
        sentAt: new Date(),
      }
    }
  }

  async sendBatch(
    items: Array<{ payload: NotificationPayload; recipient: ChannelRecipient }>
  ): Promise<ChannelSendResult[]> {
    return Promise.all(items.map((item) => this.send(item.payload, item.recipient)))
  }
}

/**
 * 创建站内消息渠道发送器。
 * 站内渠道总是启用，无需配置。
 */
export function createInAppSender(): NotificationChannelSender {
  return new InAppChannelSender()
}
