package com.sckw.message.service;

import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sckw.core.common.enums.EnvConstant;
import com.sckw.core.exception.BusinessException;
import com.sckw.core.model.page.PageResult;
import com.sckw.message.model.KwmSmsRecord;
import com.sckw.message.model.KwmSmsTemplate;
import com.sckw.message.model.KwmSmsVerifyCode;
import com.sckw.message.model.bo.*;
import com.sckw.message.utils.SmsUtil;
import com.sckw.redis.constant.RedisConstant;
import com.sckw.redis.utils.RedissonUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.UUID;

@Service
@Slf4j
@RequiredArgsConstructor
public class SmsService {

    private final KwmSmsRecordService kwmSmsRecordService;
    private final KwmSmsTemplateService kwmSmsTemplateService;
    private final KwmSmsVerifyCodeService kwmSmsVerifyCodeService;

    @Value("${spring.profiles.active}")
    private String env;

    private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    public void sendVerifyCode(SmsBo param) {
        String mobile = param.getPhone();
        String bizType = param.getType();
        String lockKey = String.format(RedisConstant.MESSAGE_SMS_VERIFY_CODE_LOCK_KEY, bizType, mobile);
        if (!RedissonUtils.tryLock(lockKey, 5L, 10L)) {
            throw new BusinessException("操作太频繁，请稍后再试");
        }
        try {
            String requestKey = String.format(RedisConstant.MESSAGE_SMS_VERIFY_CODE_REQUEST_KEY, bizType, mobile);
            if (RedissonUtils.exists(requestKey)) {
                throw new BusinessException("请勿频繁获取验证码，请60秒后再试");
            }

            String code = generateVerifyCode();
            Map<String, Object> templateParam = new HashMap<>();
            templateParam.put("code", code);

            RedissonUtils.putString(requestKey, code, RedisConstant.SMS_VERIFY_CODE_REQUEST_TIME);

            KwmSmsRecord record = buildSmsRecord(mobile, null, bizType, 1, templateParam);
            record.setSendStatus(3);

            try {
                if (EnvConstant.PROD.equals(env)) {
                    KwmSmsTemplate template = getTemplateByBizType(bizType);
                    if (template != null) {
                        SmsUtil.sendSms(mobile, template.getSignName(), template.getProviderTemplateCode(), templateParam);
                        record.setTemplateCode(template.getTemplateCode());
                        record.setTemplateContent(template.getContent());
                    } else {
                        log.error("模板不存在，请添加模块");
                    }
                } else {
                    log.warn("非正式环境");
                }
                record.setSendStatus(1);
                record.setSendTime(LocalDateTime.now());
            } catch (Exception e) {
                log.error("发送验证码短信失败，手机号：{}，原因：{}", mobile, e.getMessage(), e);
                record.setSendStatus(2);
                record.setFailReason(e.getMessage());
            }
            kwmSmsRecordService.save(record);

            String valueKey = SmsHelper.getVerifyValueKey(bizType, mobile);
            RedissonUtils.putString(valueKey, code, RedisConstant.SMS_VERIFY_CODE_VALID_TIME);

            KwmSmsVerifyCode verifyCode = new KwmSmsVerifyCode();
            verifyCode.setMobile(mobile);
            verifyCode.setBizType(bizType);
            verifyCode.setVerifyCode(code);
            verifyCode.setExpireTime(LocalDateTime.now().plusSeconds(RedisConstant.SMS_VERIFY_CODE_VALID_TIME));
            verifyCode.setVerifyStatus(0);
            verifyCode.setSendRecordId(record.getId());
            verifyCode.setCreateTime(LocalDateTime.now());
            kwmSmsVerifyCodeService.save(verifyCode);

        } finally {
            RedissonUtils.unlock(lockKey);
        }
    }

    /**
     * 获取验证码
     *
     * @param param
     * @return
     */
    public String getCode(GetVerifyCodeBo param) {
        String mobile = param.getMobile();
        String bizType = param.getBizType();

        String valueKey = SmsHelper.getVerifyValueKey(bizType, mobile);
        String cachedCode = RedissonUtils.getString(valueKey);


        if (param.getDelete()) {
            RedissonUtils.delete(valueKey);
        }

        updateVerify(mobile, bizType);
        return cachedCode;
    }

    private void updateVerify(String mobile, String bizType) {
        LambdaQueryWrapper<KwmSmsVerifyCode> queryWrapper = Wrappers.<KwmSmsVerifyCode>lambdaQuery()
                .eq(KwmSmsVerifyCode::getMobile, mobile)
                .eq(KwmSmsVerifyCode::getBizType, bizType)
                .eq(KwmSmsVerifyCode::getVerifyStatus, 0)
                .orderByDesc(KwmSmsVerifyCode::getCreateTime)
                .last("LIMIT 1");
        KwmSmsVerifyCode latestCode = kwmSmsVerifyCodeService.getOne(queryWrapper);
        if (latestCode != null) {
            latestCode.setVerifyStatus(1);
            kwmSmsVerifyCodeService.updateById(latestCode);
        }
    }

    /**
     * 校验验证码
     *
     * @param param
     * @return
     */
    public boolean verifyCode(VerifyCodeBo param) {
        String mobile = param.getMobile();
        String bizType = param.getBizType();
        String inputCode = param.getVerifyCode();

        String valueKey = SmsHelper.getVerifyValueKey(bizType, mobile);
        String cachedCode = RedissonUtils.getString(valueKey);

        if (StringUtils.isBlank(cachedCode)) {
            throw new BusinessException("验证码已过期，请重新获取");
        }
        if (!cachedCode.equals(inputCode)) {
            throw new BusinessException("验证码错误");
        }

        RedissonUtils.delete(valueKey);

        updateVerify(mobile, bizType);
        return true;
    }

    public void sendSms(SmsBo param) {
        String mobile = param.getPhone();
        String templateCode = param.getTemplateCode();
        Map<String, Object> templateParam = param.getTemplateParam();

        if (StringUtils.isBlank(templateCode)) {
            throw new BusinessException("模板编码不能为空");
        }

        KwmSmsTemplate template = getTemplateByCode(templateCode);
        if (template == null) {
            throw new BusinessException("短信模板不存在");
        }
        if (template.getStatus() != null && template.getStatus() == 0) {
            throw new BusinessException("短信模板已禁用");
        }

        String lockKey = SmsHelper.getLockKey(templateCode, mobile);
        if (!RedissonUtils.tryLock(lockKey, 5L, 10L)) {
            throw new BusinessException("操作太频繁，请稍后再试");
        }

        String requestKey = SmsHelper.getVerifyKey(templateCode, mobile);
        if (RedissonUtils.exists(requestKey)) {
            throw new BusinessException("请勿频繁获取验证码，请60秒后再试");
        }

        KwmSmsRecord record = buildSmsRecord(mobile, templateCode, param.getType(), template.getSmsType(), templateParam);
        record.setTemplateContent(template.getContent());
        record.setSendStatus(3);

        try {
            if (EnvConstant.PROD.equals(env)) {
                SmsUtil.sendSms(mobile, template.getSignName(), template.getProviderTemplateCode(),
                        templateParam);
            }
            record.setSendStatus(1);
            record.setSendTime(LocalDateTime.now());
        } catch (Exception e) {
            log.error("发送短信失败，手机号：{}，模板：{}，原因：{}", mobile, templateCode, e.getMessage(), e);
            record.setSendStatus(2);
            record.setFailReason(e.getMessage());
        }
        kwmSmsRecordService.save(record);
    }

    public void batchSendSms(BatchSendSmsBo param) {
        String templateCode = param.getTemplateCode();
        Map<String, Object> templateParam = param.getTemplateParam();

        KwmSmsTemplate template = getTemplateByCode(templateCode);
        if (template == null) {
            throw new BusinessException("短信模板不存在");
        }
        if (template.getStatus() != null && template.getStatus() == 0) {
            throw new BusinessException("短信模板已禁用");
        }

        for (String mobile : param.getMobileList()) {
            if (!mobile.matches("^1[3-9]\\d{9}$")) {
                log.warn("批量发送短信跳过无效手机号：{}", mobile);
                continue;
            }

            KwmSmsRecord record = buildSmsRecord(mobile, templateCode, param.getBizType(), template.getSmsType(), templateParam);
            record.setTemplateContent(template.getContent());
            record.setSendStatus(3);

            try {
                if (EnvConstant.PROD.equals(env)) {
                    SmsUtil.sendSms(mobile, template.getSignName(), template.getProviderTemplateCode(),
                            templateParam);
                }
                record.setSendStatus(1);
                record.setSendTime(LocalDateTime.now());
            } catch (Exception e) {
                log.error("批量发送短信失败，手机号：{}，模板：{}，原因：{}", mobile, templateCode, e.getMessage(), e);
                record.setSendStatus(2);
                record.setFailReason(e.getMessage());
            }
            kwmSmsRecordService.save(record);
        }
    }

    public PageResult pageRecord(SmsRecordQueryBo param) {
        Page<KwmSmsRecord> page = new Page<>(param.getPage(), param.getPageSize());
        LambdaQueryWrapper<KwmSmsRecord> wrapper = Wrappers.<KwmSmsRecord>lambdaQuery()
                .eq(KwmSmsRecord::getDelFlag, 0)
                .like(StringUtils.isNotBlank(param.getMobile()), KwmSmsRecord::getMobile, param.getMobile())
                .eq(StringUtils.isNotBlank(param.getTemplateCode()), KwmSmsRecord::getTemplateCode, param.getTemplateCode())
                .eq(param.getSendStatus() != null, KwmSmsRecord::getSendStatus, param.getSendStatus())
                .eq(param.getSmsType() != null, KwmSmsRecord::getSmsType, param.getSmsType())
                .eq(StringUtils.isNotBlank(param.getBizType()), KwmSmsRecord::getBizType, param.getBizType())
                .ge(StringUtils.isNotBlank(param.getStartTime()), KwmSmsRecord::getCreateTime,
                        StringUtils.isNotBlank(param.getStartTime()) ? LocalDateTime.parse(param.getStartTime(), DATE_TIME_FORMATTER) : null)
                .le(StringUtils.isNotBlank(param.getEndTime()), KwmSmsRecord::getCreateTime,
                        StringUtils.isNotBlank(param.getEndTime()) ? LocalDateTime.parse(param.getEndTime(), DATE_TIME_FORMATTER) : null)
                .orderByDesc(KwmSmsRecord::getCreateTime);
        IPage<KwmSmsRecord> result = kwmSmsRecordService.page(page, wrapper);
        return PageResult.of(result, result.getRecords());
    }

    public KwmSmsRecord getRecordDetail(Long id) {
        KwmSmsRecord record = kwmSmsRecordService.getById(id);
        if (record == null || (record.getDelFlag() != null && record.getDelFlag() == 1)) {
            throw new BusinessException("记录不存在");
        }
        return record;
    }

    public PageResult pageTemplate(SmsTemplateQueryBo param) {
        Page<KwmSmsTemplate> page = new Page<>(param.getPage(), param.getPageSize());
        LambdaQueryWrapper<KwmSmsTemplate> wrapper = Wrappers.<KwmSmsTemplate>lambdaQuery()
                .like(StringUtils.isNotBlank(param.getTemplateCode()), KwmSmsTemplate::getTemplateCode, param.getTemplateCode())
                .like(StringUtils.isNotBlank(param.getTemplateName()), KwmSmsTemplate::getTemplateName, param.getTemplateName())
                .eq(param.getSmsType() != null, KwmSmsTemplate::getSmsType, param.getSmsType())
                .eq(param.getStatus() != null, KwmSmsTemplate::getStatus, param.getStatus())
                .orderByDesc(KwmSmsTemplate::getCreateTime);
        IPage<KwmSmsTemplate> result = kwmSmsTemplateService.page(page, wrapper);
        return PageResult.of(result, result.getRecords());
    }

    public KwmSmsTemplate getTemplateDetail(Long id) {
        KwmSmsTemplate template = kwmSmsTemplateService.getById(id);
        if (template == null) {
            throw new BusinessException("模板不存在");
        }
        return template;
    }

    private KwmSmsRecord buildSmsRecord(String mobile, String templateCode, String bizType, Integer smsType, Map<String, Object> templateParam) {
        KwmSmsRecord record = new KwmSmsRecord();
        record.setBizNo(UUID.randomUUID().toString().replace("-", ""));
        record.setMobile(mobile);
        record.setTemplateCode(templateCode);
        record.setTemplateParam(templateParam != null ? JSON.toJSONString(templateParam) : null);
        record.setSmsType(smsType);
        record.setChannelCode("ALIYUN");
        record.setBizType(bizType);
        record.setRequestId(UUID.randomUUID().toString().replace("-", ""));
        record.setRetryCount(0);
        record.setMaxRetryCount(3);
        record.setDelFlag(0);
        record.setCreateTime(LocalDateTime.now());
        record.setUpdateTime(LocalDateTime.now());
        return record;
    }

    private String generateVerifyCode() {
        if (EnvConstant.PROD.equals(env)) {
            Random random = new Random();
            return String.format("%06d", random.nextInt(1000000));
        }
        return "123456";

    }

    private KwmSmsTemplate getTemplateByCode(String templateCode) {
        return kwmSmsTemplateService.getOne(
                Wrappers.<KwmSmsTemplate>lambdaQuery()
                        .eq(KwmSmsTemplate::getTemplateCode, templateCode)
                        .last("LIMIT 1")
        );
    }

    private KwmSmsTemplate getTemplateByBizType(String bizType) {
        return kwmSmsTemplateService.getOne(
                Wrappers.<KwmSmsTemplate>lambdaQuery()
                        .eq(KwmSmsTemplate::getBizType, bizType)
                        .eq(KwmSmsTemplate::getStatus, 1)
                        .last("LIMIT 1")
        );
    }

}
