package com.huimv.employment.integration.sms;

import com.aliyun.dysmsapi20170525.Client;
import com.aliyun.dysmsapi20170525.models.SendSmsRequest;
import com.aliyun.dysmsapi20170525.models.SendSmsResponse;
import com.aliyun.dysmsapi20170525.models.SendSmsResponseBody;
import com.aliyun.teaopenapi.models.Config;
import com.huimv.employment.common.exception.BizException;
import com.huimv.employment.common.exception.ErrorCode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

/**
 * 阿里云短信验证码发送实现。
 * <p>
 * 当 {@code fe.sms.mock-enabled=false} 时由 {@link SmsAutoConfiguration} 注册为本项目的
 * {@link SmsSender} 实现，通过阿里云 OpenAPI {@code SendSms} 接口下发登录验证码。
 * </p>
 * <p>
 * 前置条件：已在阿里云短信控制台完成签名、模板审核，并在 {@link SmsProperties.Aliyun} 中
 * 配置 AccessKey、签名名称、模板 CODE 等信息。模板内容需包含验证码变量（默认变量名 {@code code}）。
 * </p>
 *
 * @see SmsSender
 * @see SmsProperties
 */
public class AliyunSmsSender implements SmsSender {

    private static final Logger log = LoggerFactory.getLogger(AliyunSmsSender.class);

    /** 阿里云 SendSms 接口成功时的业务响应码 */
    private static final String SUCCESS_CODE = "OK";

    private final SmsProperties smsProperties;

    /** 阿里云 SDK 客户端，构造时初始化，线程安全可复用 */
    private final Client client;

    public AliyunSmsSender(SmsProperties smsProperties) {
        this.smsProperties = smsProperties;
        this.client = createClient();
    }

    /**
     * 调用阿里云 SendSms 接口发送登录验证码。
     *
     * @param mobile 接收短信的手机号（明文，仅用于调用第三方接口，不落库）
     * @param code   待发送的验证码，由 {@link com.huimv.employment.service.sms.SmsCodeService} 生成
     * @throws BizException 配置缺失、网络异常或阿里云返回非 OK 时抛出 {@link ErrorCode#SMS_SEND_FAILED}
     */
    @Override
    public void sendLoginCode(String mobile, String code) {
        SmsProperties.Aliyun aliyun = smsProperties.getAliyun();
        validateConfig(aliyun);

        // 组装 SendSms 请求：手机号 + 签名 + 模板 + 模板变量 JSON
        SendSmsRequest request = new SendSmsRequest()
                .setPhoneNumbers(mobile)
                .setSignName(aliyun.getSignName())
                .setTemplateCode(aliyun.getTemplateCode())
                .setTemplateParam(buildTemplateParam(aliyun.getTemplateParamName(), code));

        try {
            SendSmsResponse response = client.sendSms(request);
            SendSmsResponseBody body = response.getBody();
            // 阿里云 HTTP 200 仅表示请求到达，业务是否成功需看 body.code
            if (body == null || !SUCCESS_CODE.equals(body.getCode())) {
                String message = body == null ? "empty response" : body.getMessage();
                log.error("Aliyun SMS send failed, mobile={}, code={}, message={}", mobile, body == null ? null : body.getCode(), message);
                throw new BizException(ErrorCode.SMS_SEND_FAILED);
            }
            log.info("Aliyun SMS sent, mobile={}, bizId={}", mobile, body.getBizId());
        } catch (BizException ex) {
            throw ex;
        } catch (Exception ex) {
            log.error("Aliyun SMS send error, mobile={}", mobile, ex);
            throw new BizException(ErrorCode.SMS_SEND_FAILED);
        }
    }

    /**
     * 根据配置初始化阿里云 dysmsapi SDK Client。
     */
    private Client createClient() {
        SmsProperties.Aliyun aliyun = smsProperties.getAliyun();
        Config config = new Config()
                .setAccessKeyId(aliyun.getAccessKeyId())
                .setAccessKeySecret(aliyun.getAccessKeySecret());
        config.endpoint = aliyun.getEndpoint();
        try {
            return new Client(config);
        } catch (Exception ex) {
            throw new IllegalStateException("Init Aliyun SMS client failed", ex);
        }
    }

    /**
     * 发送前校验必填配置项，避免带着空参数调用阿里云接口。
     */
    private void validateConfig(SmsProperties.Aliyun aliyun) {
        if (!StringUtils.hasText(aliyun.getAccessKeyId())
                || !StringUtils.hasText(aliyun.getAccessKeySecret())
                || !StringUtils.hasText(aliyun.getSignName())
                || !StringUtils.hasText(aliyun.getTemplateCode())) {
            throw new BizException(ErrorCode.SMS_SEND_FAILED, "阿里云短信配置不完整");
        }
    }

    /**
     * 构造模板变量 JSON 字符串。
     * <p>示例：变量名为 code、验证码为 123456 时，返回 {@code {"code":"123456"}}。</p>
     */
    private String buildTemplateParam(String paramName, String code) {
        String name = StringUtils.hasText(paramName) ? paramName : "code";
        return "{\"" + name + "\":\"" + code + "\"}";
    }
}
