import "server-only"

/**
 * 短信通知渠道
 *
 * 支持的 Provider:
 * - aliyun: 阿里云短信（@alicloud/dysmsapi20170525，动态 import）
 * - tencent: 腾讯云短信（tencentcloud-sdk，动态 import）
 * - mock: 开发环境模拟（仅记录日志，不实际发送）
 *
 * 环境变量:
 * - SMS_PROVIDER: "aliyun" | "tencent" | "mock"（默认 mock）
 * - SMS_ACCESS_KEY_ID / SMS_ACCESS_KEY_SECRET
 * - SMS_SIGN_NAME: 短信签名
 * - SMS_TEMPLATE_CODE: 短信模板 ID
 *
 * 模板变量替换：将 payload.title / payload.content 填入模板变量 name/title/content。
 */

import type {
  NotificationPayload,
  ChannelSendResult,
  NotificationChannel,
} from "../types"
import type { NotificationChannelSender, ChannelRecipient } from "./types"

const channel: NotificationChannel = "sms"

type SmsProvider = "aliyun" | "tencent" | "mock"

const isSmsProvider = (v: unknown): v is SmsProvider =>
  v === "aliyun" || v === "tencent" || v === "mock"

/** 从环境变量读取 SMS 配置 */
function getSmsConfig(): {
  provider: SmsProvider
  accessKeyId: string | undefined
  accessKeySecret: string | undefined
  signName: string | undefined
  templateCode: string | undefined
  smsSdkAppId: string | undefined
} {
  const rawProvider = process.env.SMS_PROVIDER ?? "mock"
  return {
    provider: isSmsProvider(rawProvider) ? rawProvider : ("mock" as const),
    accessKeyId: process.env.SMS_ACCESS_KEY_ID,
    accessKeySecret: process.env.SMS_ACCESS_KEY_SECRET,
    signName: process.env.SMS_SIGN_NAME,
    templateCode: process.env.SMS_TEMPLATE_CODE,
    smsSdkAppId: process.env.SMS_SDK_APP_ID,
  }
}

/**
 * 构造短信模板变量。
 * 阿里云/腾讯云模板使用 ${name} / ${title} / ${content} 占位符。
 */
function buildTemplateParams(payload: NotificationPayload): Record<string, string> {
  return {
    title: payload.title,
    content: payload.content,
    type: payload.type,
  }
}

/** Mock 短信发送器（开发环境使用） */
class MockSmsSender implements NotificationChannelSender {
  readonly channel = channel

  async send(
    payload: NotificationPayload,
    recipient: ChannelRecipient
  ): Promise<ChannelSendResult> {
    const params = buildTemplateParams(payload)
    // 开发环境仅记录日志，不实际发送
    console.info(
      `[MockSms] send to ${recipient.phone ?? "(no phone)"}: title="${payload.title}" params=`,
      params
    )
    return {
      channel,
      success: true,
      messageId: `mock-sms-${Date.now()}`,
      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)))
  }
}

/** 阿里云短信发送器 */
class AliyunSmsSender implements NotificationChannelSender {
  readonly channel = channel
  private config: ReturnType<typeof getSmsConfig>

  constructor() {
    this.config = getSmsConfig()
  }

  async send(
    payload: NotificationPayload,
    recipient: ChannelRecipient
  ): Promise<ChannelSendResult> {
    if (!recipient.phone) {
      return { channel, success: false, error: "Missing recipient phone", sentAt: new Date() }
    }
    if (!this.config.accessKeyId || !this.config.accessKeySecret) {
      return { channel, success: false, error: "SMS_ACCESS_KEY_ID/SECRET not configured", sentAt: new Date() }
    }

    try {
      // 动态 import 阿里云 SDK，避免增加构建体积
      const { default: Dysmsapi } = await import("@alicloud/dysmsapi20170525")
      const { default: OpenApi } = await import("@alicloud/openapi-client")
      const { default: Credential } = await import("@alicloud/credentials")

      const credential = new Credential({
        accessKeyId: this.config.accessKeyId,
        accessKeySecret: this.config.accessKeySecret,
      })
      const apiConfig = new OpenApi({ credential })
      apiConfig.endpoint = "dysmsapi.aliyuncs.com"
      const client = new Dysmsapi(apiConfig)

      const { SendSmsRequest } = await import("@alicloud/dysmsapi20170525")
      const request = new SendSmsRequest({
        phoneNumbers: recipient.phone,
        signName: this.config.signName,
        templateCode: this.config.templateCode,
        templateParam: JSON.stringify(buildTemplateParams(payload)),
      })

      const response = await client.sendSms(request)
      const code = response?.body?.code
      const success = code === "OK"
      return {
        channel,
        success,
        messageId: response?.body?.bizId ?? undefined,
        error: success ? undefined : response?.body?.message,
        sentAt: new Date(),
      }
    } catch (e) {
      return {
        channel,
        success: false,
        error: e instanceof Error ? e.message : "Aliyun SMS send 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)))
  }
}

/** 腾讯云短信发送器 */
class TencentSmsSender implements NotificationChannelSender {
  readonly channel = channel
  private config: ReturnType<typeof getSmsConfig>

  constructor() {
    this.config = getSmsConfig()
  }

  async send(
    payload: NotificationPayload,
    recipient: ChannelRecipient
  ): Promise<ChannelSendResult> {
    if (!recipient.phone) {
      return { channel, success: false, error: "Missing recipient phone", sentAt: new Date() }
    }
    if (!this.config.accessKeyId || !this.config.accessKeySecret) {
      return { channel, success: false, error: "SMS_ACCESS_KEY_ID/SECRET not configured", sentAt: new Date() }
    }

    try {
      // 动态 import 腾讯云 SDK
      const tencentcloud = await import("tencentcloud-sdk-nodejs")
      const SmsClient = tencentcloud.sms.v20210111.Client

      const client = new SmsClient({
        credential: {
          secretId: this.config.accessKeyId,
          secretKey: this.config.accessKeySecret,
        },
        region: "ap-guangzhou",
        profile: {
          httpProfile: { endpoint: "sms.tencentcloudapi.com" },
        },
      })

      const params = buildTemplateParams(payload)
      const response = await client.SendSms({
        PhoneNumberSet: [`+86${recipient.phone}`],
        SmsSdkAppId: this.config.smsSdkAppId ?? "",
        SignName: this.config.signName ?? "",
        TemplateId: this.config.templateCode ?? "",
        TemplateParamSet: [params.title, params.content],
      })

      const sendStatus = response?.SendStatusSet?.[0]
      const success = sendStatus?.Code === "Ok"
      return {
        channel,
        success,
        messageId: sendStatus?.SerialNo ?? undefined,
        error: success ? undefined : sendStatus?.Message,
        sentAt: new Date(),
      }
    } catch (e) {
      return {
        channel,
        success: false,
        error: e instanceof Error ? e.message : "Tencent SMS send 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)))
  }
}

/**
 * 创建 SMS 渠道发送器（根据 SMS_PROVIDER 环境变量选择实现）。
 * 默认使用 Mock 实现，确保开发环境无外部服务时也可用。
 */
export function createSmsSender(): NotificationChannelSender {
  const config = getSmsConfig()
  switch (config.provider) {
    case "aliyun":
      return new AliyunSmsSender()
    case "tencent":
      return new TencentSmsSender()
    case "mock":
    default:
      return new MockSmsSender()
  }
}
