package com.slodon.b2b2c.model.msg;

import cn.hutool.core.thread.NamedThreadFactory;
import cn.hutool.extra.mail.MailAccount;
import cn.hutool.extra.mail.MailUtil;
import com.alibaba.fastjson.JSONObject;
import com.beust.jcommander.ParameterException;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.slodon.b2b2c.core.config.DomainUrlUtil;
import com.slodon.b2b2c.core.constant.SMSConst;
import com.slodon.b2b2c.core.exception.MallException;
import com.slodon.b2b2c.core.sms.SmsRequest;
import com.slodon.b2b2c.core.sms.SmsResponse;
import com.slodon.b2b2c.core.util.StringUtil;
import com.slodon.b2b2c.sms.DySmsSender;
import com.slodon.b2b2c.sms.TencentSmsSender;
import com.slodon.b2b2c.sms.YunPianSmsSender;
import com.slodon.b2b2c.sms.base.SmsSender;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.List;
import java.util.concurrent.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 消息发送model层
 */
@Slf4j
@Component
public class MsgSendModel {

    /**
     * 创建一个线程池
     */
    private ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat("thread-call-runner-%d").build();

    private ExecutorService pool = new ThreadPoolExecutor(SMSConst.DEFAULT_RUN_THREAD_NUM, SMSConst.DEFAULT_RUN_THREAD_NUM,
            100L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(), threadFactory);

    private ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(SMSConst.DEFAULT_RUN_THREAD_NUM, SMSConst.DEFAULT_RUN_THREAD_NUM,
            100L, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>(2),
            new NamedThreadFactory("sms-thread-pool", false), new ThreadPoolExecutor.AbortPolicy());

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 发送验证码短信
     *
     * @param mobile 手机号
     * @return SmsResponse
     */
    @SneakyThrows
    public SmsResponse sendVerifyCode(String mobile) {
        if (StringUtil.isEmpty(mobile)) {
            throw new MallException("请指定要发送的手机号码");
        }
        SmsRequest smsRequest = new SmsRequest();
        smsRequest.setSmsType(SMSConst.VERIFY_SMS);
        smsRequest.setMobile(mobile);
        smsRequest.setTemplateId("notification_sms_ali_register_sms_template");
//        smsRequest.setSmsType("");
//        smsRequest.setTemplateContent("【{1}】您的验证码是{2}，请不要把验证码泄露给其他人。");

        SmsResponse smsResponse = null;
        try {
            if (pool.isShutdown()) {
                pool = Executors.newFixedThreadPool(SMSConst.DEFAULT_RUN_THREAD_NUM);
            }
            smsResponse = (SmsResponse) pool.submit(new SmsCall(smsRequest)).get();
            //将随机数存在redis中
            stringRedisTemplate.opsForValue().set(mobile, smsResponse.getVerifyCode(), 60L * 5, TimeUnit.SECONDS);
        } catch (Exception e) {
            log.error("[MsgSendModel][sendVerifyCode]发送验证码短信异常:", e);
            //关闭线程池
            pool.shutdown();
        }
        return smsResponse;
    }


    /**
     * 发送通知短信
     *
     * @param smsRequest 请求参数
     */
    public void sendSms(SmsRequest smsRequest) {
        if (StringUtil.isEmpty(smsRequest.getMobile())) {
            throw new MallException("请指定要发送的手机号码");
        }
        threadPoolExecutor.submit(() -> {
            //根据系统配置的发送方式，获取短信发送对象
            SmsSender smsSender;
            switch (DomainUrlUtil.SEND_SMS_TYPE) {
                case 1:
                    //腾讯云发送
                    smsSender = new TencentSmsSender(stringRedisTemplate);
                    break;
                case 2:
                    //云片发送
                    smsSender = new YunPianSmsSender(stringRedisTemplate);
                    break;
                default:
                    throw new ParameterException("参数错误");
            }
            smsSender.sendSms(smsRequest);
        });
    }

    /**
     * 发送邮件
     *
     * @param toAddress 邮件接收地址
     * @param subject   主题
     * @param content   内容
     */
    public void sendMail(String toAddress, String subject, String content) {
        MailAccount account = new MailAccount();
        account.setHost(stringRedisTemplate.opsForValue().get("notification_email_smtp_host"));
        String emailPort = stringRedisTemplate.opsForValue().get("notification_email_smtp_port");
        account.setPort(StringUtil.isEmpty(emailPort) ? 465 : Integer.parseInt(emailPort));
        account.setFrom(stringRedisTemplate.opsForValue().get("notification_email_sender_address"));
        account.setUser(stringRedisTemplate.opsForValue().get("notification_email_sender_name"));
        account.setPass(stringRedisTemplate.opsForValue().get("notification_email_sender_password"));
        account.setAuth(true);
        // todo 邮箱ssl暂时开启
        account.setStarttlsEnable(true);
        account.setSslEnable(false);
        account.setDebug(true);
        MailUtil.send(account, toAddress, subject, content, false);
    }

    /**
     * 发送含有html邮件
     *
     * @param toAddress 邮件接收地址
     * @param subject   主题
     * @param content   内容
     */
    public void sendHtmlMail(String toAddress, String subject, String content) {
        MailAccount account = new MailAccount();
        account.setHost(stringRedisTemplate.opsForValue().get("notification_email_smtp_host"));
        String emailPort = stringRedisTemplate.opsForValue().get("notification_email_smtp_port");
        account.setPort(StringUtil.isEmpty(emailPort) ? 465 : Integer.parseInt(emailPort));
        account.setFrom(stringRedisTemplate.opsForValue().get("notification_email_sender_address"));
        account.setUser(stringRedisTemplate.opsForValue().get("notification_email_sender_name"));
        account.setPass(stringRedisTemplate.opsForValue().get("notification_email_sender_password"));
        account.setAuth(true);
        // todo 邮箱ssl暂时关闭
        account.setStarttlsEnable(true);
        account.setSslEnable(false);
        account.setDebug(true);
        MailUtil.send(account, toAddress, subject, content, true);
    }

    /**
     * 发送含有html邮件
     *
     * @param toAddress 邮件接收地址
     * @param subject   主题
     * @param content   内容
     */
    public void sendHtmlMail(List<String> toAddress, String subject, String content) {
        MailAccount account = new MailAccount();
        account.setHost(stringRedisTemplate.opsForValue().get("notification_email_smtp_host"));
        String emailPort = stringRedisTemplate.opsForValue().get("notification_email_smtp_port");
        account.setPort(StringUtil.isEmpty(emailPort) ? 465 : Integer.parseInt(emailPort));
        account.setFrom(stringRedisTemplate.opsForValue().get("notification_email_sender_address"));
        account.setUser(stringRedisTemplate.opsForValue().get("notification_email_sender_name"));
        account.setPass(stringRedisTemplate.opsForValue().get("notification_email_sender_password"));
        account.setAuth(true);
        // todo 邮箱ssl暂时关闭
        account.setStarttlsEnable(true);
        account.setSslEnable(false);
        account.setDebug(true);
        MailUtil.send(account, toAddress, subject, content, true);
    }

    class SmsCall implements Callable<Object> {

        private SmsRequest smsRequest;

        SmsCall(SmsRequest smsRequest) {
            this.smsRequest = smsRequest;
        }

        @Override
        public Object call() {
            //根据系统配置的发送方式，获取短信发送对象
            SmsSender smsSender;
            switch (DomainUrlUtil.SEND_SMS_TYPE) {
                case 1:
                    //腾讯云发送
                    smsSender = new TencentSmsSender(stringRedisTemplate);
                    break;
                case 2:
                    //云片发送
                    smsSender = new YunPianSmsSender(stringRedisTemplate);
                    break;
                case 3:
                    //阿里云发送
                    smsSender = new DySmsSender(stringRedisTemplate);
                    break;
                default:
                    throw new MallException("参数错误");
            }
            return smsSender.sendSms(smsRequest);
        }
    }

}
