package com.m2pool.auth.service.impl;

import com.alibaba.fastjson.JSON;
import com.m2pool.auth.entity.EmailCodeEntity;
import com.m2pool.auth.entity.GetEmailCodeEntity;
import com.m2pool.auth.entity.GetLoginEmailCodeEntity;
import com.m2pool.auth.service.MailService;
import com.m2pool.common.core.RedisTransKey;
import com.m2pool.common.core.Result.R;
import com.m2pool.common.core.constant.SecurityConstants;
import com.m2pool.common.core.utils.CodeUtils;
import com.m2pool.common.core.utils.StringUtils;
import com.m2pool.common.redis.service.RedisService;
import com.m2pool.common.security.utils.SecurityUtils;
import com.m2pool.system.api.RemoteUserService;
import com.m2pool.system.api.entity.EmailTemplateEntity;
import com.m2pool.system.api.model.LoginUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.FileSystemResource;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;

import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.io.File;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @Description TODO
 * @Date 2024/6/12 15:08
 * @Author dy
 */
@Service
public class MaliServiceImpl implements MailService {
    /**
     * 注入邮件工具类
     */
    @Autowired
    private JavaMailSenderImpl javaMailSender;

    @Autowired
    private RemoteUserService remoteUserService;

    @Autowired
    private TemplateEngine templateEngine;

    @Autowired
    private RedisService redisService;

    @Value("${spring.mail.username}")
    private String sendMailer;


    @Value("${image.prefix}")
    private String imagePrefix;

    public static String EMAIL_REGEX="^\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*$";

    /**
     * 检测邮件信息类
     * @param to
     * @param subject
     * @param text
     */
    private void checkMail(String to,String subject,String text){
        if(StringUtils.isEmpty(to)){
            throw new RuntimeException("邮件收信人不能为空");
        }
        if(StringUtils.isEmpty(subject)){
            throw new RuntimeException("邮件主题不能为空");
        }
        if(StringUtils.isEmpty(text)){
            throw new RuntimeException("邮件内容不能为空");
        }
    }

    /**
     * 发送纯文本邮件
     * @param to
     * @param subject
     * @param text
     */
    @Override
    public void sendTextMailMessage(String to,String subject,String text){

        try {
            //true 代表支持复杂的类型
            MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(javaMailSender.createMimeMessage(),true);
            //邮件发信人
            mimeMessageHelper.setFrom(sendMailer);
            //邮件收信人  1或多个
            mimeMessageHelper.setTo(to.split(","));
            //邮件主题
            mimeMessageHelper.setSubject(subject);
            //邮件内容
            mimeMessageHelper.setText(text);
            //邮件发送时间
            mimeMessageHelper.setSentDate(new Date());

            //发送邮件
            javaMailSender.send(mimeMessageHelper.getMimeMessage());
            //System.out.println("发送邮件成功："+sendMailer+"->"+to);

        } catch (Exception e) {
            e.printStackTrace();
            //System.out.println("发送邮件失败："+e.getMessage());
        }
    }


    /**
     * 发送HTML邮件
     * @param to
     * @param subject
     * @param templateName 模版名
     * @param variables 需要映射到html上的动态内容
     * @throws MessagingException
     */
    public void sendHtmlEmail(String to, String subject, String templateName, Map<String, Object> variables) throws MessagingException {
        // 创建 MimeMessage 对象
        MimeMessage message = javaMailSender.createMimeMessage();
        MimeMessageHelper helper = new MimeMessageHelper(message, true);


        //邮件发信人
        helper.setFrom(sendMailer);

        // 收件人一个活多个
        helper.setTo(to.split(","));
        helper.setSubject(subject);

        // 创建 Thymeleaf 上下文并添加变量
        Context context = new Context();
        //设置图片访问前缀
        variables.put("imagePrefix", imagePrefix);
        context.setVariables(variables);

        // 处理 HTML 模板
        String htmlContent = templateEngine.process(templateName, context);

        // 设置邮件内容为 HTML
        helper.setText(htmlContent, true);

        //邮件发送时间
        helper.setSentDate(new Date());

        // 发送邮件
        javaMailSender.send(message);
        System.out.println("发送邮件成功："+sendMailer+"->"+to);
    }



    @Override
    public void sendHtmlMailMessage(EmailTemplateEntity entity){
        try {
            sendHtmlEmail(entity.getEmail(),entity.getSubject(),entity.getTemplateName(),entity.getData());
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("发送邮件失败："+e.getMessage());
        }
    }

    /**
     * 发送带附件的邮件
     * @param to      邮件收信人
     * @param subject 邮件主题
     * @param content 邮件内容
     * @param filePath 附件路径
     */
    @Override
    public void sendAttachmentMailMessage(String to,String subject,String content,String filePath){
        try {
            //true 代表支持复杂的类型
            MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(javaMailSender.createMimeMessage(),true);
            //邮件发信人
            mimeMessageHelper.setFrom(sendMailer);
            //邮件收信人  1或多个
            mimeMessageHelper.setTo(to.split(","));
            //邮件主题
            mimeMessageHelper.setSubject(subject);
            //邮件内容   true 代表支持html
            mimeMessageHelper.setText(content,true);
            //邮件发送时间
            mimeMessageHelper.setSentDate(new Date());
            //添加邮件附件
            FileSystemResource file = new FileSystemResource(new File(filePath));
            String fileName = file.getFilename();
            mimeMessageHelper.addAttachment(fileName, file);

            //发送邮件
            javaMailSender.send(mimeMessageHelper.getMimeMessage());
            //System.out.println("发送邮件成功："+sendMailer+"->"+to);

        } catch (Exception e) {
            e.printStackTrace();
            //System.out.println("发送邮件失败："+e.getMessage());
        }
    }

    /**
     * 发送账号注册邮箱验证码
     * @param to
     * @param code
     */
    @Override
    public void sendCodeMailMessage(String to, String code) {
        //String subject = "账号注册，邮箱验证码";
        //String text = "注册验证码10分钟内有效:\n\t"+code;
        Map<String, Object> content = new HashMap<>();
        content.put("code",code);
        content.put("text","The verification code for registration is valid for 10 minutes");
        EmailTemplateEntity message = new EmailTemplateEntity(to,"Account registration, email verification code","emailCode-en",content);
        sendHtmlMailMessage(message);
    }

    /**
     * 发送账号登录邮箱验证码
     * @param to
     * @param code
     */
    @Override
    public void sendLoginCodeMailMessage(String to, String code) {
        //String subject = "用户登录，邮箱验证码";
        //String text = "登录验证码10分钟内有效:\n\t"+code;
        Map<String, Object> content = new HashMap<>();
        content.put("code",code);
        content.put("text","Login verification code is valid within 10 minutes");
        EmailTemplateEntity entity = new EmailTemplateEntity(to,"User login, email verification code","emailCode-en",content);
        sendHtmlMailMessage(entity);
    }



    @Override
    public void sendResetPwdMailMessage(String to, String code) {
        //String subject = "账号重置密码，邮箱验证码";
        //String text = "您正在重置密码，如果不是您本人操作，请忽略。验证码10分钟内有效:\n\t"+code;

        Map<String, Object> content = new HashMap<>();
        content.put("code",code);
        content.put("text","You are resetting your password. If this is not done by you, please ignore it. The verification code is valid for 10 minutes.");
        EmailTemplateEntity entity = new EmailTemplateEntity(to,"Reset account password, email verification code","emailCode-en",content);
        sendHtmlMailMessage(entity);
    }

    @Override
    public void sendUpdatePwdMailMessage(String to, String code) {
        //String subject = "修改密码，邮箱验证码";
        //String text = "您正在修改密码，如果不是您本人操作，请忽略。验证码10分钟内有效:\n\t"+code;

        Map<String, Object> content = new HashMap<>();
        content.put("code",code);
        content.put("text","You are currently modifying your password. If this is not done by you, please ignore it. The verification code is valid for 10 minutes.");
        EmailTemplateEntity entity = new EmailTemplateEntity(to,"Change password, email verification code","emailCode-en",content);
        sendHtmlMailMessage(entity);
    }

    @Override
    public R<?> emailCode(GetEmailCodeEntity entity) {
        String email = entity.getEmail();
        if(!StringUtils.isBlank(email)){
            if(!email.matches(EMAIL_REGEX)){
                return  R.fail("邮箱格式错误");
            }
        }else {
            return  R.fail("601,\"邮箱不能为空\"");
        }

        //手动格式验证

        //判断用户是不是恶意刷邮箱，在规定时间内进行的
        if (redisService.hasKey(RedisTransKey.getEmailKey(email))) {
            Object o = redisService.getCacheObject(RedisTransKey.getEmailKey(email));//user:emailCode:email

            EmailCodeEntity emailCodeEntity = JSON.parseObject(JSON.toJSONString(o), EmailCodeEntity.class);
            if (emailCodeEntity.getTimes() > 4) {
                return R.fail("请求次数过多，请10分钟后再试,(同一用户10分钟内只能请求4次)");
            } else {

                String emailCode = CodeUtils.creatCode(6);
                emailCodeEntity.setEmailCode(emailCode);


                //if(!email.equals(emailCodeEntity.getEmail())){
                //    //email与缓存中所存邮箱不同 则请求次数重置为1
                //    emailCodeEntity.setTimes(1);
                //}else {
                //    emailCodeEntity.setTimes(emailCodeEntity.getTimes() + 1);
                //}

                emailCodeEntity.setTimes(emailCodeEntity.getTimes() + 1);
                long overTime = redisService.getExpire(RedisTransKey.setEmailKey(email));
                redisService.setCacheObject(RedisTransKey.setEmailKey(email), emailCodeEntity, overTime, TimeUnit.SECONDS
                );
                sendCodeMailMessage(email, emailCodeEntity.getEmailCode());
            }
        } else {
            R<LoginUser> userByEmail = remoteUserService.getUserInfo(email, SecurityConstants.INNER);

            //if (userByName.getData() != null) {
            //    return R.fail(603,"用户名"+username+"已被注册");
            //} else
            if(userByEmail.getData() !=null){

                return R.fail(604,"邮箱"+email+"已被注册");
            } else {
                String emailCode = CodeUtils.creatCode(6);
                // 最多允许用户在10分钟内发送2次的邮箱验证
                // 0s倒计时后用户可以再发送验证码，但是间隔在10分钟内只能再发送1次
                EmailCodeEntity emailCodeEntity = new EmailCodeEntity(
                        email, emailCode,1
                );
                //设置失效时间10分钟
                redisService.setCacheObject(RedisTransKey.getEmailKey(email), emailCodeEntity,
                        10L, TimeUnit.MINUTES
                );
                sendCodeMailMessage(email, emailCodeEntity.getEmailCode());
            }
        }
        return R.success("请求成功，验证码已经发送至用户邮箱");

    }

    @Override
    public R<?> loginCode(GetLoginEmailCodeEntity entity) {
        String email = entity.getAccount();
        if(!StringUtils.isBlank(email)){
            if(!email.matches(EMAIL_REGEX)){
                return  R.fail("邮箱格式错误");
            }
        }else {
            return R.fail(601,"邮箱不能为空");
        }
        //String username = entity.getUserName();

        //if(StringUtils.isNull(username)){
        //    return R.fail(602,"用户名不能为空");
        //}

        //判断用户是不是恶意刷邮箱，在规定时间内进行的
        if (redisService.hasKey(RedisTransKey.getLoginKey(email))) {
            Object o = redisService.getCacheObject(RedisTransKey.getLoginKey(email));//user:login:email

            EmailCodeEntity emailCodeEntity = JSON.parseObject(JSON.toJSONString(o), EmailCodeEntity.class);
            if (emailCodeEntity.getTimes() > 4) {
                return R.fail("请求次数过多，请10分钟后再试,(同一用户10分钟内只能请求4次)");
            } else {

                String emailCode = CodeUtils.creatCode(6);
                emailCodeEntity.setEmailCode(emailCode);

                //if(!email.equals(emailCodeEntity.getEmail())){
                //    //email与缓存中所存邮箱不同 则请求次数重置为1
                //    emailCodeEntity.setTimes(1);
                //}else {
                //    emailCodeEntity.setTimes(emailCodeEntity.getTimes() + 1);
                //}

                emailCodeEntity.setTimes(emailCodeEntity.getTimes() + 1);
                long overTime = redisService.getExpire(RedisTransKey.setLoginKey(email));
                redisService.setCacheObject(RedisTransKey.setLoginKey(email), emailCodeEntity, overTime, TimeUnit.SECONDS
                );
                sendLoginCodeMailMessage(email, emailCodeEntity.getEmailCode());
            }
        } else {
            R<LoginUser> userByEmail = remoteUserService.getUserInfo(email, SecurityConstants.INNER);

            //if (userByName.getData() != null) {
            //    return R.fail(603,"用户名"+username+"已被注册");
            //} else
            if(StringUtils.isNull(userByEmail.getData())){

                return R.fail(606,"邮箱"+email+"未注册");
            } else {
                String emailCode = CodeUtils.creatCode(6);
                // 最多允许用户在10分钟内发送2次的邮箱验证
                // 0s倒计时后用户可以再发送验证码，但是间隔在10分钟内只能再发送1次
                EmailCodeEntity emailCodeEntity = new EmailCodeEntity(
                        email, emailCode,1
                );
                //设置失效时间10分钟
                redisService.setCacheObject(RedisTransKey.getLoginKey(email), emailCodeEntity,
                        10L, TimeUnit.MINUTES
                );
                sendLoginCodeMailMessage(email, emailCodeEntity.getEmailCode());
            }
        }
        return R.success("请求成功，验证码已经发送至用户邮箱");
    }

    @Override
    public R<?> AddCreditCode(GetEmailCodeEntity entity) {
        String email = entity.getEmail();
        String username = entity.getUserName();

        if(StringUtils.isNull(email)){
            return R.fail(601,"邮箱不能为空");
        }
        if(StringUtils.isNull(username)){
            return R.fail(602,"用户名不能为空");
        }

        //判断用户是不是恶意刷邮箱，在规定时间内进行的
        if (redisService.hasKey(RedisTransKey.getAddCreditEmailKey(email))) {
            long t1 = System.currentTimeMillis();
            Object o = redisService.getCacheObject(RedisTransKey.getAddCreditEmailKey(email));//user:addCreditEmailCode:email

            com.m2pool.system.api.entity.EmailCodeEntity emailCodeEntity = JSON.parseObject(JSON.toJSONString(o), com.m2pool.system.api.entity.EmailCodeEntity.class);
            if (emailCodeEntity.getTimes() > 4) {
                return R.fail("请求次数过多，请10分钟后再试,(同一用户10分钟内只能请求4次)");
            } else {

                String emailCode = CodeUtils.creatCode(6);
                emailCodeEntity.setEmailCode(emailCode);
                emailCodeEntity.setUserName(username);


                emailCodeEntity.setTimes(emailCodeEntity.getTimes() + 1);
                long overTime = redisService.getExpire(RedisTransKey.getAddCreditEmailKey(email));
                redisService.setCacheObject(RedisTransKey.setAddCreditEmailKey(email), emailCodeEntity, overTime, TimeUnit.SECONDS
                );
                sendCodeMailMessage(email, emailCodeEntity.getEmailCode());
            }
            long t2 = System.currentTimeMillis();
            System.out.println("处理业务1耗时"+(t2-t1));
        } else {
            long t1 = System.currentTimeMillis();
            String emailCode = CodeUtils.creatCode(6);
                // 最多允许用户在10分钟内发送2次的邮箱验证
                // 0s倒计时后用户可以再发送验证码，但是间隔在10分钟内只能再发送1次
            com.m2pool.system.api.entity.EmailCodeEntity emailCodeEntity = new com.m2pool.system.api.entity.EmailCodeEntity     (
                        username  , email, emailCode,1
                );
                //设置失效时间10分钟
                redisService.setCacheObject(RedisTransKey.getAddCreditEmailKey(email), emailCodeEntity,
                        10L, TimeUnit.MINUTES
                );
                String subject = "用户提现邮箱验证码";
                String text = "提现验证码,10分钟内有效:\n\t"+emailCodeEntity.getEmailCode();
            long t2 = System.currentTimeMillis();
            System.out.println("处理业务2耗时"+(t2-t1));
                sendTextMailMessage(email,subject,text);
            long t3 = System.currentTimeMillis();
            System.out.println("发送邮箱耗时"+(t3-t2));
        }
        return R.success("请求成功，验证码已经发送至用户邮箱");

    }

    @Override
    public R<?> resetPwdCode(GetEmailCodeEntity entity) {
        String email = entity.getEmail();
        if(!StringUtils.isBlank(email)){
            if(!email.matches(EMAIL_REGEX)){
                return R.fail("邮箱格式错误");
            }
        }else {
            return R.fail(601,"邮箱为不能为空");
        }

        //通过邮箱获取用户
        R<LoginUser> userByEmail = remoteUserService.getUserInfo(email, SecurityConstants.INNER);

        if(StringUtils.isNull(userByEmail.getData())){
            return R.fail("邮箱"+email+"未被注册，请检查邮箱是否正确");
        }

        //判断用户是不是恶意刷邮箱，在规定时间内进行的
        if (redisService.hasKey(RedisTransKey.getResetPwdKey(email))) {

            Object o = redisService.getCacheObject(RedisTransKey.getResetPwdKey(email));//user:restPwdCode:email

            EmailCodeEntity emailCodeEntity = JSON.parseObject(JSON.toJSONString(o), EmailCodeEntity.class);
            if (emailCodeEntity.getTimes() >= 5) {
                return R.fail("请求次数过多，请10分钟后再试");
            } else {
                //这里就不去判断两次绑定的邮箱是不是一样的了，不排除第一次输入错了邮箱的情况
                String emailCode = CodeUtils.creatCode(6);
                emailCodeEntity.setEmailCode(emailCode);
                emailCodeEntity.setTimes(emailCodeEntity.getTimes() + 1);
                long overTime = redisService.getExpire(RedisTransKey.getResetPwdKey(email));
                redisService.setCacheObject(RedisTransKey.getResetPwdKey(email), emailCodeEntity, overTime, TimeUnit.SECONDS
                );
                sendResetPwdMailMessage(email, emailCodeEntity.getEmailCode());
            }
        } else {
            String emailCode = CodeUtils.creatCode(6);
            // 最多允许用户在10分钟内发送2次的邮箱验证
            // 0s倒计时后用户可以再发送验证码，但是间隔在10分钟内只能再发送1次
            EmailCodeEntity emailCodeEntity = new EmailCodeEntity(
                      email, emailCode,1
            );
            //设置失效时间10分钟
            redisService.setCacheObject(RedisTransKey.getResetPwdKey(email), emailCodeEntity,
                    10L, TimeUnit.MINUTES
            );
            sendResetPwdMailMessage(email, emailCodeEntity.getEmailCode());
        }
        return R.success("请求成功，重置密码验证码已经发送至用户邮箱");

    }

    @Override
    public R<?> updatePwdCode() {
        String email = SecurityUtils.getUsername();
        if(StringUtils.isBlank(email)){
            return R.fail("token解析失败");
        }
        //通过邮箱获取用户
        R<LoginUser> userByEmail = remoteUserService.getUserInfo(email, SecurityConstants.INNER);

        if(StringUtils.isNull(userByEmail.getData())){
            return R.fail("token解析异常");
        }

        //判断用户是不是恶意刷邮箱，在规定时间内进行的
        if (redisService.hasKey(RedisTransKey.getUpdatePwdKey(email))) {

            Object o = redisService.getCacheObject(RedisTransKey.getUpdatePwdKey(email));//user:updatePwdCode:email

            EmailCodeEntity emailCodeEntity = JSON.parseObject(JSON.toJSONString(o), EmailCodeEntity.class);
            if (emailCodeEntity.getTimes() >= 5) {
                return R.fail("请求次数过多，请10分钟后再试");
            } else {
                //这里就不去判断两次绑定的邮箱是不是一样的了，不排除第一次输入错了邮箱的情况
                String emailCode = CodeUtils.creatCode(6);
                emailCodeEntity.setEmailCode(emailCode);
                emailCodeEntity.setTimes(emailCodeEntity.getTimes() + 1);
                long overTime = redisService.getExpire(RedisTransKey.getUpdatePwdKey(email));
                redisService.setCacheObject(RedisTransKey.getUpdatePwdKey(email), emailCodeEntity, overTime, TimeUnit.SECONDS
                );
                sendUpdatePwdMailMessage(email, emailCodeEntity.getEmailCode());
            }
        } else {
            String emailCode = CodeUtils.creatCode(6);
            // 最多允许用户在10分钟内发送2次的邮箱验证
            // 0s倒计时后用户可以再发送验证码，但是间隔在10分钟内只能再发送1次
            EmailCodeEntity emailCodeEntity = new EmailCodeEntity(
                    email, emailCode,1
            );
            //设置失效时间10分钟
            redisService.setCacheObject(RedisTransKey.getUpdatePwdKey(email), emailCodeEntity,
                    10L, TimeUnit.MINUTES
            );
            sendUpdatePwdMailMessage(email, emailCodeEntity.getEmailCode());
        }
        return R.success("请求成功，修改密码验证码已经发送至用户邮箱");

    }

}
