package com.m2pool.pool.service.impl;

import com.alibaba.fastjson.JSON;
import com.m2pool.common.core.Result.R;
import com.m2pool.common.core.utils.CodeUtils;
import com.m2pool.common.core.utils.StringUtils;
import com.m2pool.common.core.utils.sign.RsaUtils;
import com.m2pool.common.core.web.Result.AjaxResult;
import com.m2pool.common.redis.service.RedisService;
import com.m2pool.common.security.utils.SecurityUtils;
import com.m2pool.pool.dto.GoogleInfoDto;
import com.m2pool.pool.entity.GoogleInfo;
import com.m2pool.pool.entity.UserGoogleAuthInfo;
import com.m2pool.pool.mapper.GoogleAuthMapper;
import com.m2pool.pool.service.GoogleAuthService;
import com.m2pool.common.core.utils.GoogleAuthenticator;
import com.m2pool.pool.utils.QrCodeUtils;
import com.m2pool.pool.vo.EmailVo;
import com.m2pool.pool.vo.GoogleBindVo;
import com.m2pool.pool.vo.GoogleCloseVo;
import com.m2pool.system.api.RemoteMailService;
import com.m2pool.system.api.entity.EmailCodeEntity;
import com.m2pool.system.api.entity.EmailEntity;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

/**
 * @Description TODO
 * @Date 2024/8/22 14:50
 * @Author 杜懿
 */
@Service
public class GoogleAuthServiceImpl implements GoogleAuthService {

    @Autowired
    private GoogleAuthMapper googleAuthMapper;

    @Autowired
    private RemoteMailService mailService;

    @Autowired
    private RedisService redisService;

    @Value("${myenv.domain}")
    private String domain;


    @Override
    public AjaxResult ifBind() {
        String email = SecurityUtils.getUsername();
        if(StringUtils.isNull(email)){
            return AjaxResult.error("token解析异常");
        }
        boolean result = googleAuthMapper.checkIfBindByEmail(email);
        return AjaxResult.success(result);
    }

    @Override
    public AjaxResult emailIfBind(EmailVo vo) {
        String email = StringUtils.clean(vo.getEmail());
        if(StringUtils.isBlank(email)){
            return AjaxResult.error("邮箱不能为空");
        }
        boolean result = googleAuthMapper.checkIfBindByEmail(email);
        return AjaxResult.success(result);
    }

    /**
     * 获取验证码和二维码
     * @return
     */
    @Override
    public AjaxResult getBindInfo() {
        String email = SecurityUtils.getUsername();
        if(StringUtils.isNull(email)){
            return AjaxResult.error("token解析异常");
        }
        GoogleInfo info = googleAuthMapper.getGoogleInfoByEmail(email);
        if (StringUtils.isNull(info)){
            return AjaxResult.error("未能从token获取到所需内容,请勿擅自修改token");
        }

        GoogleInfoDto dto = new GoogleInfoDto();
        if(StringUtils.isBlank(info.getSecret())){
            //生成谷歌验证码
            String secret = GoogleAuthenticator.getSecretKey();
            String qrCodeText = GoogleAuthenticator.getQrCodeText(secret, email, domain);
            String img = QrCodeUtils.creatRrCode(qrCodeText, 200, 200);

            boolean ifExist = googleAuthMapper.checkSecretIfExist(secret);
            if(ifExist){
                secret = GoogleAuthenticator.getSecretKey();
                qrCodeText = GoogleAuthenticator.getQrCodeText(secret, email, domain);
                img = QrCodeUtils.creatRrCode(qrCodeText,200,200);

                ifExist = googleAuthMapper.checkSecretIfExist(secret);
                if(ifExist){
                    return AjaxResult.error("网络异常,请稍后再试");
                }
            }
            dto.setSecret(secret);
            dto.setImg(img);

        }else {
            //数据库已有谷歌验证码 直接返回
            BeanUtils.copyProperties(info,dto);
            dto.setImg(QrCodeUtils.creatRrCode( GoogleAuthenticator.getQrCodeText(dto.getSecret(),email  , domain),200,200));
        }
        return AjaxResult.success(dto);
    }

    @Override
    public AjaxResult bindGoogle(GoogleBindVo vo) {
        // 参数校验
        if (StringUtils.isNull(vo)){
            return AjaxResult.error("未获取到请求参数");
        }
        String email = SecurityUtils.getUsername();
        if(StringUtils.isNull(email)){
            return AjaxResult.error("token解析异常");
        }

        String password="";
        try {
            password = RsaUtils.decryptByPrivateKey(vo.getPwd());
            password = StringUtils.clean(password);
        }catch (Exception e){
            return AjaxResult.error(401,"加密密码传参有误");
        }
        System.out.println("email :"+email);
        // 根据邮箱查询是否已绑定
        UserGoogleAuthInfo info = googleAuthMapper.getUserInfoByEmail(email);
        if (StringUtils.isNull(info)){
            return AjaxResult.error("未能从token获取到所需内容,请勿擅自修改token");
        }
        System.out.println("info :"+info);

        if(StringUtils.isBlank(info.getSecret())){
            //未绑定 正常走绑定流程
            //校验gcode
            boolean gResult = GoogleAuthenticator.checkCode(vo.getSecret(), vo.getGCode(), System.currentTimeMillis());
            if(!gResult){
                return AjaxResult.error("谷歌验证码错误");
            }
            //校验邮箱验证码
            String redisKey = "google:"+email+":code";
            if(redisService.hasKey(redisKey)){

                Object o = redisService.getCacheObject(redisKey);//google:email:code

                EmailCodeEntity emailCodeEntity = JSON.parseObject(JSON.toJSONString(o), EmailCodeEntity.class);

                //验证验证码
                if(!vo.getECode().equals(emailCodeEntity.getEmailCode())){
                    return AjaxResult.error("邮箱验证码错误");
                }
            }else {
                return AjaxResult.error("邮箱验证码 未获取或已过期(有效期10分钟)，请重新获取验证码");
            }

            //校验密码
            if (!SecurityUtils.matchesPassword(password, info.getPwd())){
                return AjaxResult.error("密码错误");
            }
            //入库
            UserGoogleAuthInfo bingInfo = new UserGoogleAuthInfo();
            bingInfo.setSecret(vo.getSecret());
            bingInfo.setStatus(1);
            bingInfo.setEmail(info.getEmail());
            boolean bingResult = googleAuthMapper.bingGoogleAuthenticator(bingInfo);
            if(bingResult){
                return AjaxResult.success();
            }else {
                return AjaxResult.error("请求服务器失败,请重试");
            }

        }else {
            if(info.getStatus()  == 2){
                return AjaxResult.error("您绑定但是关闭了双重验证,请重新打开");
            }if(info.getStatus()  == 1){
                return AjaxResult.error("当前用户已绑定过谷歌登录器");
            }else {
                return AjaxResult.error("当前用户已绑定过谷歌登录器.");
            }
        }

    }

    @Override
    public AjaxResult getBindCode() {
        String email = SecurityUtils.getUsername();
        if(StringUtils.isNull(email)){
            return AjaxResult.error("token解析异常");
        }

        //判断用户是不是恶意刷邮箱，在规定时间内进行的
        String redisKey = "google:"+email+":code";
        if (redisService.hasKey(redisKey)) {
            Object o = redisService.getCacheObject(redisKey);//google:email:code

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

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


                emailCodeEntity.setTimes(emailCodeEntity.getTimes() + 1);
                long overTime = redisService.getExpire(redisKey);
                redisService.setCacheObject(redisKey, emailCodeEntity, overTime, TimeUnit.SECONDS
                );
                return sendEmail(email,emailCode);
            }
        } else {
            String emailCode = CodeUtils.creatCode(6);
            // 最多允许用户在10分钟内发送2次的邮箱验证
            // 0s倒计时后用户可以再发送验证码，但是间隔在10分钟内只能再发送1次
            EmailCodeEntity emailCodeEntity = new EmailCodeEntity();
            emailCodeEntity.setEmail(email);
            emailCodeEntity.setEmailCode(emailCode);
            emailCodeEntity.setTimes(1);
            //设置失效时间10分钟
            redisService.setCacheObject(redisKey, emailCodeEntity,
                    10L, TimeUnit.MINUTES
            );
            return sendEmail(email,emailCode);
        }


    }


    @Override
    public AjaxResult closeStepTwp(GoogleCloseVo vo) {
        // 参数校验
        if (StringUtils.isNull(vo)){
            return AjaxResult.error("未获取到请求参数");
        }
        String email = SecurityUtils.getUsername();
        if(StringUtils.isNull(email)){
            return AjaxResult.error("token解析异常");
        }

        System.out.println("email :"+email);
        // 根据邮箱查询是否已绑定
        UserGoogleAuthInfo info = googleAuthMapper.getUserInfoByEmail(email);
        if (StringUtils.isNull(info)){
            return AjaxResult.error("未能从token获取到所需内容,请勿擅自修改token");
        }
        System.out.println("info :"+info);

        if(StringUtils.isBlank(info.getSecret())){
            return AjaxResult.success();
        }else {

            //已绑定 正常走关闭谷歌验证流程
            //校验gcode
            boolean gResult = GoogleAuthenticator.checkCode(info.getSecret(), vo.getGCode(), System.currentTimeMillis());
            if(!gResult){
                return AjaxResult.error("谷歌验证码错误");
            }
            //校验邮箱验证码
            String redisKey = "google:"+email+":close";
            if(redisService.hasKey(redisKey)){

                Object o = redisService.getCacheObject(redisKey);//google:email:close

                EmailCodeEntity emailCodeEntity = JSON.parseObject(JSON.toJSONString(o), EmailCodeEntity.class);

                //验证验证码
                if(!vo.getECode().equals(emailCodeEntity.getEmailCode())){
                    return AjaxResult.error("邮箱验证码错误");
                }
            }else {
                return AjaxResult.error("邮箱验证码 未获取或已过期(有效期10分钟)，请重新获取验证码");
            }

            //入库
            boolean bingResult = googleAuthMapper.closeGoogleAuthenticator(info);
            if(bingResult){
                return AjaxResult.success();
            }else {
                return AjaxResult.error("请求服务器失败,请重试");
            }
        }
    }

    @Override
    public AjaxResult getCloseCode() {
        String email = SecurityUtils.getUsername();
        if(StringUtils.isNull(email)){
            return AjaxResult.error("token解析异常");
        }

        //判断用户是不是恶意刷邮箱，在规定时间内进行的
        String redisKey = "google:"+email+":close";
        if (redisService.hasKey(redisKey)) {
            Object o = redisService.getCacheObject(redisKey);//google:email:close

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

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

                emailCodeEntity.setTimes(emailCodeEntity.getTimes() + 1);
                long overTime = redisService.getExpire(redisKey);
                redisService.setCacheObject(redisKey, emailCodeEntity, overTime, TimeUnit.SECONDS
                );
                return sendEmail(email,emailCode);
            }
        } else {
            String emailCode = CodeUtils.creatCode(6);
            // 最多允许用户在10分钟内发送2次的邮箱验证
            // 0s倒计时后用户可以再发送验证码，但是间隔在10分钟内只能再发送1次
            EmailCodeEntity emailCodeEntity = new EmailCodeEntity();
            emailCodeEntity.setEmail(email);
            emailCodeEntity.setEmailCode(emailCode);
            emailCodeEntity.setTimes(1);
            //设置失效时间10分钟
            redisService.setCacheObject(redisKey, emailCodeEntity,
                    10L, TimeUnit.MINUTES
            );
            return sendCloseEmail(email,emailCode);
        }
    }

    public AjaxResult sendEmail(String email,String code){
        String text = "您正在绑定谷歌验证器！\n" +
                "您的邮箱验证验证码是:\n\t"+code +
                "\n此验证码10分钟有效。";
        EmailEntity emailEntity = new EmailEntity();
        emailEntity.setEmail(email);
        emailEntity.setSubject("[M2Pool] 邮箱验证码");
        emailEntity.setText(text);
        R<?> r = mailService.sendTextMail(emailEntity);
        if(r.getCode() == 200){
            return AjaxResult.success();
        }else {
            return AjaxResult.error(r.getCode(),r.getMsg());
        }
    }



    public AjaxResult sendCloseEmail(String email,String code){
        String text = "M2Pool:\n" +
                "您正在解绑谷歌验证器！\n" +
                "您的邮箱验证验证码是:\n\t"+code +
                "\n此验证码10分钟有效。";
        EmailEntity emailEntity = new EmailEntity();
        emailEntity.setEmail(email);
        emailEntity.setSubject("[M2Pool] 邮箱验证码");
        emailEntity.setText(text);
        R<?> r = mailService.sendTextMail(emailEntity);
        if(r.getCode() == 200){
            return AjaxResult.success();
        }else {
            return AjaxResult.error(r.getCode(),r.getMsg());
        }
    }
}
