package com.ruoyi.framework.web.service.sms;

import java.util.Collections;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.alibaba.fastjson2.JSON;
import com.aliyun.auth.credentials.Credential;
import com.aliyun.auth.credentials.provider.StaticCredentialProvider;
import com.aliyun.sdk.service.dysmsapi20170525.AsyncClient;
import com.aliyun.sdk.service.dysmsapi20170525.models.SendSmsRequest;
import com.aliyun.sdk.service.dysmsapi20170525.models.SendSmsResponse;
import com.aliyun.sdk.service.dysmsapi20170525.models.SendSmsResponseBody;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.framework.config.properties.SmsProperties;
import com.ruoyi.framework.config.properties.SmsProperties.Aliyun;

/**
 * 开发态短信网关：基于 {@code alibabacloud-dysmsapi20170525} 封装 SendSms。
 * <p>
 * <b>两种模式</b>
 * <ul>
 *   <li><b>日志 Stub</b>：{@code sms.aliyun.dry-run=true}，或未配置 AccessKey/签名/模板时，
 *       不调用阿里云，仅将 OTP 写入日志（便于本地联调）</li>
 *   <li><b>真实发送</b>：配置完整且 {@code dry-run=false} 时，调用 dysmsapi SendSms 下发短信</li>
 * </ul>
 * </p>
 */
@Component
public class AliyunSmsGatewayClient implements SmsGatewayClient, DisposableBean
{
    private static final Logger log = LoggerFactory.getLogger(AliyunSmsGatewayClient.class);

    private static final String SEND_OK = "OK";

    @Autowired
    private SmsProperties smsProperties;

    /** 懒加载，仅在需要真实发送时创建 */
    private volatile AsyncClient asyncClient;

    @Override
    public boolean sendLoginCode(String mobile, String code)
    {
        Aliyun aliyun = smsProperties.getAliyun();
        if (aliyun.shouldUseLogStub())
        {
            logStubSend(mobile, code, aliyun);
            return true;
        }
        return sendByAliyun(mobile, code, aliyun);
    }

    /**
     * 开发态 Stub：验证码写入日志，手机号脱敏。
     */
    private void logStubSend(String mobile, String code, Aliyun aliyun)
    {
        String reason;
        if (!aliyun.isEnabled())
        {
            reason = "sms.aliyun.enabled=false";
        }
        else if (aliyun.isDryRun())
        {
            reason = "sms.aliyun.dry-run=true";
        }
        else
        {
            reason = "AccessKey/签名/模板未配置完整";
        }
        log.info("【短信Stub】{}，向 {} 发送登录验证码：{}（未调用阿里云 API）",
                reason, maskMobile(mobile), code);
    }

    /**
     * 调用阿里云 dysmsapi SendSms（异步 SDK，此处同步等待结果）。
     */
    private boolean sendByAliyun(String mobile, String code, Aliyun aliyun)
    {
        try
        {
            String templateParam = JSON.toJSONString(Collections.singletonMap("code", code));
            SendSmsRequest request = SendSmsRequest.builder()
                    .phoneNumbers(mobile)
                    .signName(aliyun.getSignName())
                    .templateCode(aliyun.getTemplateCode())
                    .templateParam(templateParam)
                    .build();

            SendSmsResponse response = getClient(aliyun)
                    .sendSms(request)
                    .get(aliyun.getRequestTimeoutSeconds(), TimeUnit.SECONDS);

            SendSmsResponseBody body = response != null ? response.getBody() : null;
            if (body != null && SEND_OK.equalsIgnoreCase(StringUtils.trim(body.getCode())))
            {
                log.info("【阿里云短信】已向 {} 发送登录验证码，RequestId={}",
                        maskMobile(mobile), body.getRequestId());
                return true;
            }

            String errCode = body != null ? body.getCode() : "NULL_BODY";
            String errMsg = body != null ? body.getMessage() : "empty response body";
            log.error("【阿里云短信】发送失败 mobile={} code={} message={}",
                    maskMobile(mobile), errCode, errMsg);
            return false;
        }
        catch (InterruptedException ex)
        {
            Thread.currentThread().interrupt();
            log.error("【阿里云短信】发送被中断 mobile={}", maskMobile(mobile), ex);
            return false;
        }
        catch (Exception ex)
        {
            log.error("【阿里云短信】发送异常 mobile={}", maskMobile(mobile), ex);
            return false;
        }
    }

    private AsyncClient getClient(Aliyun aliyun)
    {
        if (asyncClient == null)
        {
            synchronized (this)
            {
                if (asyncClient == null)
                {
                    asyncClient = AsyncClient.builder()
                            .credentialsProvider(StaticCredentialProvider.create(
                                    Credential.builder()
                                            .accessKeyId(aliyun.getAccessKeyId())
                                            .accessKeySecret(aliyun.getAccessKeySecret())
                                            .build()))
                            .region(aliyun.getRegion())
                            .build();
                }
            }
        }
        return asyncClient;
    }

    /** 日志中手机号脱敏：138****1111 */
    private String maskMobile(String mobile)
    {
        if (mobile == null || mobile.length() < 7)
        {
            return "****";
        }
        return mobile.substring(0, 3) + "****" + mobile.substring(mobile.length() - 4);
    }

    @Override
    public void destroy()
    {
        if (asyncClient != null)
        {
            try
            {
                asyncClient.close();
            }
            catch (Exception ex)
            {
                log.warn("关闭阿里云短信 AsyncClient 异常", ex);
            }
            finally
            {
                asyncClient = null;
            }
        }
    }
}
