/**
 * 阿里云短信服务客户端
 *
 * 接入: dysmsapi.aliyuncs.com (短信服务在国内是全局服务,所有调用走 cn-hangzhou)
 * 文档: https://help.aliyun.com/document_detail/419298.html
 *
 * 环境变量:
 *   SMS_ACCESS_KEY      RAM 子账号 AccessKey ID
 *   SMS_SECRET_KEY      RAM 子账号 AccessKey Secret
 *   SMS_SIGN_NAME       已审核通过的签名 (例: 广州气元科技)
 *   SMS_TEMPLATE_CODE   已审核通过的模板 Code (例: SMS_506210397)
 *
 * 模板内容必须严格使用 ${code} 占位符,例如:
 *   "您的验证码是 ${code},5 分钟内有效,请勿泄露。"
 */
import Dysmsapi, * as $Dysmsapi from "@alicloud/dysmsapi20170525";
import * as $OpenApi from "@alicloud/openapi-client";
import * as $Util from "@alicloud/tea-util";

let client: Dysmsapi | null = null;

function getClient(): Dysmsapi | null {
  if (client) return client;
  const accessKeyId = process.env.SMS_ACCESS_KEY;
  const accessKeySecret = process.env.SMS_SECRET_KEY;
  if (!accessKeyId || !accessKeySecret) return null;
  const config = new $OpenApi.Config({ accessKeyId, accessKeySecret });
  config.endpoint = "dysmsapi.aliyuncs.com";
  client = new Dysmsapi(config);
  return client;
}

export interface SendOtpResult {
  ok: boolean;
  /** 阿里云返回的 BizId,排查问题时给阿里云工单用 */
  bizId?: string;
  /** 阿里云错误码 / 失败原因 */
  errorCode?: string;
  errorMessage?: string;
}

/**
 * 发送 6 位验证码短信。
 * 返回 ok=true 表示阿里云已受理 (用户收到短信通常在 30 秒内);
 * ok=false 时 errorCode 给出原因 (如 isv.MOBILE_NUMBER_ILLEGAL / isv.BUSINESS_LIMIT_CONTROL 等)。
 *
 * 若 SMS_ACCESS_KEY/SMS_SECRET_KEY 未配置,函数直接返回 ok=false 且 errorCode='SMS_NOT_CONFIGURED',
 * 调用方可根据该信号 fallback 到 dev console.log 输出验证码。
 */
export async function sendOtpSms(
  phone: string,
  code: string,
): Promise<SendOtpResult> {
  const c = getClient();
  const signName = process.env.SMS_SIGN_NAME;
  const templateCode = process.env.SMS_TEMPLATE_CODE;
  if (!c || !signName || !templateCode) {
    return { ok: false, errorCode: "SMS_NOT_CONFIGURED" };
  }

  const req = new $Dysmsapi.SendSmsRequest({
    phoneNumbers: phone,
    signName,
    templateCode,
    templateParam: JSON.stringify({ code }),
  });

  try {
    const resp = await c.sendSmsWithOptions(req, new $Util.RuntimeOptions({}));
    const body = resp.body;
    if (body?.code === "OK") {
      return { ok: true, bizId: body.bizId };
    }
    return {
      ok: false,
      errorCode: body?.code ?? "UNKNOWN",
      errorMessage: body?.message,
    };
  } catch (e) {
    const msg = e instanceof Error ? e.message : String(e);
    return { ok: false, errorCode: "EXCEPTION", errorMessage: msg };
  }
}
