package shop.alien.store.util.ali;

import com.aliyun.dysmsapi20170525.Client;
import com.aliyun.dysmsapi20170525.models.SendSmsRequest;
import com.aliyun.dysmsapi20170525.models.SendSmsResponse;
import com.aliyun.teaopenapi.models.Config;
import com.aliyun.teautil.models.RuntimeOptions;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;
import shop.alien.entity.store.StoreVerificationCode;
import shop.alien.mapper.StoreVerificationCodeMapper;
import shop.alien.store.config.BaseRedisService;
import shop.alien.store.config.NacosConfig;
import shop.alien.util.common.RandomCreateUtil;

import java.util.Date;

/**
 * 阿里云验证码配置
 *
 * @author ssk
 * @version 1.0
 * @date 2024/12/12 10:17
 */
@Slf4j
@Component
@RefreshScope
@RequiredArgsConstructor
public class AliSms {
    private final BaseRedisService baseRedisService;

    private final NacosConfig nacosConfig;

    private final StoreVerificationCodeMapper storeVerificationCodeMapper;

    @Value("${ali.sms.accessKeyId}")
    private String accessKeyId;

    @Value("${ali.sms.accessKeySecret}")
    private String accessKeySecret;

    @Value("${ali.sms.endPoint}")
    private String endPoint;

    @Value("${ali.sms.signName}")
    private String signName;

    @Value("${ali.sms.templateCode}")
    private String templateCode;

    @Value("${ali.sms.codeTimeOut}")
    private Long codeTimeOut;

    @Value("${ali.sms.templateAccount}")
    private String templateAccount;

    @Value("${ali.sms.templateAccountCode:}")
    private String templateAccountCode;



    /**
     * 发送验证码
     *
     * @param phone        手机号
     * @param appType      端区分(0:用户, 1:商家, 2:商家web端)
     * @param businessType 业务类型 (0:登录, 1:修改密码, 2:注册, 3:修改手机号, 4:注销店铺, 5:注销账号, 6:忘记密码)
     * @return 验证码
     */
    public Integer sendSms(String phone, Integer appType, Integer businessType) {
        log.info("AliSmsConfig.sendSms?phone={}&appType={}&businessType={}", phone, appType, businessType);
        try {
            String appTypeStr = appType == 0 ? "user" : (appType == 1 ? "store" : "store_platform");
            String businessTypeStr;
            switch (businessType) {
                case 0:
                    //登录
                    businessTypeStr = "login";
                    break;
                case 1:
                    //修改密码
                    businessTypeStr = "modify_password";
                    break;
                case 2:
                    //注册
                    businessTypeStr = "register";
                    break;
                case 3:
                    //修改手机号
                    businessTypeStr = "modify_phone";
                    break;
                case 4:
                    //注销店铺
                    businessTypeStr = "cancel_store";
                    break;
                case 5:
                    //注销账号
                    businessTypeStr = "cancel_account";
                    break;
                case 6:
                    //忘记密码
                    businessTypeStr = "forget_password";
                    break;
                case 7:
                    //忘记支付密码
                    businessTypeStr = "forget_pay_password";
                    break;
                default:
                    businessTypeStr = "login";
            }
            // -----------------测试用手机号--------------------------------------------------------------------------------------------
            if (nacosConfig.getTestPhone().contains(phone)) {
                // 验证码发送成功，将验证码保存到redis中 设置60秒过期
                baseRedisService.setString("verification_" + appTypeStr + "_" + businessTypeStr + "_" + phone, "123456", codeTimeOut);
                saveVerificationCode(appType, businessType, phone, "123456");
                return 123456;
            }
            // -----------------测试用手机号--------------------------------------------------------------------------------------------

            Config config = new Config()
                    .setEndpoint(endPoint)
                    .setAccessKeyId(accessKeyId)
                    .setAccessKeySecret(accessKeySecret);
            Integer code = RandomCreateUtil.getRandomNum(100000, 999999);

            // 构建发送请求
            SendSmsRequest sendSmsRequest = new SendSmsRequest()
                    // 设置签名
                    .setSignName(signName)
                    // 设置模板
                    .setTemplateCode(templateCode)
                    // 设置手机号为参数传入的值
                    .setPhoneNumbers(phone)
                    // 设置模板参数为传入的验证码
                    .setTemplateParam("{\"code\":\"" + code + "\"}");
            // 运行时选择，可以设置不同的属性来配置运行时环境的参数。
            RuntimeOptions runtime = new RuntimeOptions();
            Client client = new Client(config);
            // 复制代码运行请自行打印 API 的返回值
            SendSmsResponse sendSmsResponse = client.sendSmsWithOptions(sendSmsRequest, runtime);
            if (!"OK".equals(sendSmsResponse.getBody().getCode())) {
                return null;
            }
            // 验证码发送成功，将验证码保存到redis中 设置60秒过期
            baseRedisService.setString("verification_" + appTypeStr + "_" + businessTypeStr + "_" + phone, code.toString(), codeTimeOut);
            saveVerificationCode(appType, businessType, phone, code.toString());

            return code;
        } catch (Exception e) {
            log.error("AliSmsConfig.sendSms ERROR Msg={}", e.getMessage());
            return null;
        }
    }

    /**
     * 校验短信验证码
     *
     * @param phone        手机号
     * @param appType      端区分(0:用户, 1:商家, 2:商家web端)
     * @param businessType 业务类型 (0:登录, 1:修改密码, 2:注册, 3:修改手机号, 4:注销店铺, 5:注销账号, 6:忘记密码)
     * @param code         用户输入的验证码
     * @return 校验结果 true-校验成功 false-校验失败
     */
    public boolean checkSmsCode(String phone, Integer appType, Integer businessType, Integer code) {
        log.info("AliSms.checkSmsCode?phone={}&appType={}&businessType={}&code={}", phone, appType, businessType, code);
        try {
            // 构建Redis key，与sendSms方法中的key格式保持一致
            String appTypeStr = appType == 0 ? "user" : (appType == 1 ? "store" : "store_platform");
            String businessTypeStr;
            switch (businessType) {
                case 0:
                    businessTypeStr = "login";
                    break;
                case 1:
                    businessTypeStr = "modify_password";
                    break;
                case 2:
                    businessTypeStr = "register";
                    break;
                case 3:
                    businessTypeStr = "modify_phone";
                    break;
                case 4:
                    businessTypeStr = "cancel_store";
                    break;
                case 5:
                    businessTypeStr = "cancel_account";
                    break;
                case 6:
                    businessTypeStr = "forget_password";
                    break;
                case 7:
                    businessTypeStr = "forget_pay_password";
                    break;
                default:
                    businessTypeStr = "login";
            }
            
            String verifyKey = "verification_" + appTypeStr + "_" + businessTypeStr + "_" + phone;
            
            // 从Redis中获取验证码
            String cacheCode = baseRedisService.getString(verifyKey);
            
            // 验证码不存在或已过期
            if (cacheCode == null || cacheCode.trim().isEmpty()) {
                log.warn("验证码不存在或已过期，phone={}, appType={}, businessType={}", phone, appType, businessType);
                return false;
            }
            
            // 比较验证码（去除空格）
            boolean isValid = cacheCode.trim().equals(String.valueOf(code).trim());
            
            if (isValid) {
                // 验证成功，删除验证码（防止重复使用）
                baseRedisService.delete(verifyKey);
                log.info("验证码校验成功，phone={}, appType={}, businessType={}", phone, appType, businessType);
            } else {
                log.warn("验证码校验失败，phone={}, appType={}, businessType={}, 期望值={}, 实际值={}", 
                        phone, appType, businessType, cacheCode, code);
            }
            
            return isValid;
        } catch (Exception e) {
            log.error("AliSms.checkSmsCode ERROR Msg={}", e.getMessage(), e);
            return false;
        }
    }

    private void saveVerificationCode(Integer appType, Integer businessType, String phone, String code) {
        try {
            StoreVerificationCode entity = new StoreVerificationCode();
            entity.setAppType(appType);
            entity.setBusinessType(businessType);
            entity.setPhone(phone);
            entity.setCode(code);
            Date now = new Date();
            entity.setCreatedTime(now);
            entity.setUpdatedTime(now);
            entity.setDeleteFlag(0);
            storeVerificationCodeMapper.insert(entity);
        } catch (Exception ex) {
            log.error("AliSms.saveVerificationCode ERROR Msg={}", ex.getMessage(), ex);
        }
    }

    /**
     * JSON字符串转义，防止特殊字符破坏JSON格式
     */
    private String escapeJsonString(String str) {
        if (str == null) {
            return "";
        }
        return str.replace("\\", "\\\\")
                  .replace("\"", "\\\"")
                  .replace("\n", "\\n")
                  .replace("\r", "\\r")
                  .replace("\t", "\\t");
    }

    /**
     * 发送律师短信信息（账号密码通知）
     * @param phone        手机号
     * @param userName     用户名
     * @param password     密码
     * @return 1-发送成功, null-发送失败
     */
    public Integer sendLawyerSms(String phone, String userName, String password) {
        log.info("AliSmsConfig.sendLawyerSms?phone={}&userName={}", phone, userName);
        try {
            Config config = new Config()
                    .setEndpoint(endPoint)
                    .setAccessKeyId(accessKeyId)
                    .setAccessKeySecret(accessKeySecret);

            // 构建模板参数JSON，必须符合阿里云短信模板参数格式
            // 模板内容：您在律所管理平台的账号已创建成功,账号名称为${userName},登录密码为${password}.
            // 模板CODE：SMS_499205254
            // 变量：userName（用户昵称）、password（其他号码）
            // 参数名必须与模板中的变量名一致（去掉${}），格式必须是有效的JSON
            String templateParam = String.format("{\"userName\":\"%s\",\"password\":\"%s\"}", 
                    escapeJsonString(userName), 
                    escapeJsonString(password));

            // 使用账号密码短信模板代码
            // 优先级：templateAccountCode > templateAccount（如果以SMS_开头）> templateCode
            String accountTemplateCode;
            if (templateAccountCode != null && !templateAccountCode.trim().isEmpty()) {
                accountTemplateCode = templateAccountCode;
            } else if (templateAccount != null && templateAccount.startsWith("SMS_")) {
                // 如果templateAccount配置的是模板代码（以SMS_开头），则使用它
                accountTemplateCode = templateAccount;
            } else {
                accountTemplateCode = templateCode;
            }

            log.info("AliSmsConfig.sendLawyerSms 准备发送短信，phone={}, userName={}, templateCode={}, templateParam={}", 
                    phone, userName, accountTemplateCode, templateParam);

            // 构建发送请求
            SendSmsRequest sendSmsRequest = new SendSmsRequest()
                    // 设置签名
                    .setSignName(signName)
                    // 设置模板代码（账号密码短信模板）
                    .setTemplateCode(accountTemplateCode)
                    // 设置手机号
                    .setPhoneNumbers(phone)
                    // 设置模板参数（必须是有效的JSON格式）
                    .setTemplateParam(templateParam);
            
            // 运行时选择，可以设置不同的属性来配置运行时环境的参数。
            RuntimeOptions runtime = new RuntimeOptions();
            Client client = new Client(config);
            // 调用阿里云短信API
            SendSmsResponse sendSmsResponse = client.sendSmsWithOptions(sendSmsRequest, runtime);
            
            String responseCode = sendSmsResponse.getBody().getCode();
            String responseMessage = sendSmsResponse.getBody().getMessage();
            String bizId = sendSmsResponse.getBody().getBizId(); // 业务ID，用于查询发送状态
            
            // 记录完整的响应信息
            log.info("AliSmsConfig.sendLawyerSms API响应详情，phone={}, responseCode={}, responseMessage={}, bizId={}", 
                    phone, responseCode, responseMessage, bizId);
            
            if (!"OK".equals(responseCode)) {
                log.error("AliSmsConfig.sendLawyerSms 短信发送失败，phone={}, userName={}, templateCode={}, templateParam={}, responseCode={}, responseMessage={}, bizId={}", 
                        phone, userName, accountTemplateCode, templateParam, responseCode, responseMessage, bizId);
                return null;
            }
            
            // 即使返回OK，也可能存在其他问题，记录详细信息便于排查
            log.info("AliSmsConfig.sendLawyerSms 短信发送成功（API返回OK），phone={}, userName={}, bizId={}, templateCode={}, templateParam={}", 
                    phone, userName, bizId, accountTemplateCode, templateParam);
            
            // 如果bizId为空，可能是异常情况
            if (bizId == null || bizId.trim().isEmpty()) {
                log.warn("AliSmsConfig.sendLawyerSms 警告：API返回OK但bizId为空，可能存在问题，phone={}, responseMessage={}", 
                        phone, responseMessage);
            }
            
            return 1;
        } catch (Exception e) {
            log.error("AliSmsConfig.sendLawyerSms ERROR phone={}, userName={}, Msg={}", phone, userName, e.getMessage(), e);
            return null;
        }
    }

}
