package com.liquidnet.service.adam.service.impl;

import com.liquidnet.common.cache.redis.util.RedisUtil;
import com.liquidnet.commons.lang.util.MD5;
import com.liquidnet.service.adam.common.AdamErrorCode;
import com.liquidnet.service.adam.constant.AdamRedisConstants;
import com.liquidnet.service.adam.dto.base.AdamResultDto;
import com.liquidnet.service.adam.entity.AdamUser;
import com.liquidnet.service.adam.service.IAdamUserPasswordService;
import com.liquidnet.service.adam.service.IAdamUserService;
import com.liquidnet.service.adam.service.sys.IAdamSysEmailService;
import com.liquidnet.service.adam.service.sys.IAdamSysMessageService;
import com.liquidnet.service.adam.service.sys.IAdamSystemService;
import com.liquidnet.service.adam.util.DateUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.Date;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * <p>
 * 用户信息 服务实现类
 * </p>
 *
 * @author liquidnet
 * @since 2020-09-16
 */
@Slf4j
@Service
public class AdamUserPasswordServiceImpl implements IAdamUserPasswordService {
    @Value("${liquidnet.conf.user.md5Prefix}")
    private String prefix;

    @Value("${liquidnet.conf.user.md5Suffix}")
    private String suffix;

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private IAdamUserService adamUserService;

    @Autowired
    private IAdamSysMessageService adamSysMessageService;

    @Autowired
    private IAdamSystemService adamSystemService;

    @Autowired
    private IAdamSysEmailService adamSysEmailService;

    @Override
    public String getPasswordMD5(String password) {
        return MD5.getStrMD5(prefix + password + suffix);
    }

    // 校验密码格式
    @Override
    public AdamResultDto checkPasswordFormat(String password) {
        String reg = "^(?=.*[0-9])(?=.*[a-zA-Z])[^/].{7,23}$";
        Pattern r = Pattern.compile(reg);
        Matcher m = r.matcher(password);
        if (m.matches()) {
            return AdamResultDto.success();
        }
        return AdamResultDto.failure(AdamErrorCode.PWD_FORMAT_INVALID);
    }

    @Override
    public AdamResultDto checkLoginPassword(AdamUser adamUser, String password) {
        // 校验密码失败次数,大于等于7次不能登录,次日才允许登录,通过忘记密码重置密码时,需要重置密码失败次数
        String passwordErrorKey = AdamRedisConstants.USER_PASSWORD_ERROR_KEY + adamUser.getEmail();
        String passwordErrorKeyValue = (String) redisUtil.get(passwordErrorKey);
        if (StringUtils.isEmpty(passwordErrorKeyValue)) {
            passwordErrorKeyValue = "0";
        }
        if (Integer.parseInt(passwordErrorKeyValue) >= 7) {
            return AdamResultDto.failure(AdamErrorCode.ADAM_USER_PASSWORD_ERROR_7);
        }
        boolean flag = this.getPasswordMD5(password).equalsIgnoreCase(adamUser.getPassword());

        if (!flag) {
            int errorNo = Integer.parseInt(passwordErrorKeyValue) + 1;
            redisUtil.set(passwordErrorKey, String.valueOf(errorNo), DateUtil.getRemainSecondsOneDay(new Date()));
            if (errorNo == 5) {
                return AdamResultDto.failure(AdamErrorCode.ADAM_USER_PASSWORD_ERROR_5);
            } else if (errorNo == 7) {
                return AdamResultDto.failure(AdamErrorCode.ADAM_USER_PASSWORD_ERROR_7);
            }
            return AdamResultDto.failure(AdamErrorCode.ADAM_USER_PW_0020016);
        }
        if (!StringUtils.isEmpty(passwordErrorKeyValue)) {
            redisUtil.del(passwordErrorKey);
        }

        return AdamResultDto.success();
    }

    @Override
    public AdamResultDto update(String userId, String oldPw, String newPw) {
        AdamUser adamUser = adamUserService.selectById(userId);
        if (adamUser == null) {
            return AdamResultDto.failure(AdamErrorCode.ADAM001_PARAM_ERROR);
        }

        // 验证用户密码
        if (!this.getPasswordMD5(oldPw).equals(adamUser.getPassword())) {
            return AdamResultDto.failure(AdamErrorCode.ADAM_USER_PW_0020016);
        }
        // 验证新密码格式
        AdamResultDto checkPasswordFormat = checkPasswordFormat(newPw);
        if (!checkPasswordFormat.isSuccess()) {
            return checkPasswordFormat;
        }
        AdamUser upUser = new AdamUser();
        upUser.setId(userId);
        upUser.setPassword(this.getPasswordMD5(newPw));
        upUser.setUpdateTime(LocalDateTime.now());
        int i1 = adamUserService.updateById(upUser);
        return i1 > 0 ? AdamResultDto.success() : AdamResultDto.failure(AdamErrorCode.ADAM001_OPERATION_FAILED);
    }

    @Override
    public AdamResultDto forgetVerifyCodeSend(String email, String verifyMethod) {
        if (StringUtils.isEmpty(verifyMethod)) {
            return AdamResultDto.failure(AdamErrorCode.ADAM001_PARAM_ERROR);
        }
        AdamUser adamUser = adamUserService.getUserByEmail(email);
        if (adamUser == null) {
            return AdamResultDto.failure(AdamErrorCode.EMAIL_NOT_REGIS);
        }

        if ("phone".equals(verifyMethod) && StringUtils.isEmpty(adamUser.getPhoneNumber())) {
            return AdamResultDto.failure(AdamErrorCode.ADAM_USER_PASSWORD_FORGET_PHONE);
        }
        String redisKey = AdamRedisConstants.USER_PASSWORD_FORGET_KEY + email;
//        // 获取redis key是否存在
//        Object o = redisUtil.get(redisKey);
//        if (o != null) {
//            return AdamResultDto.failure(AdamErrorCode.ADAM001_VERIFYCODE_SENT);
//        }
        String verifyCode = adamSystemService.generateVerifyCode();
        String redisValue = verifyCode;
        // 设置redis key 验证码过期时间
        redisUtil.set(redisKey, redisValue, TimeUnit.MINUTES.toSeconds(2));
        log.info("forget verify code send,email=[{}],verifyCode=[{}]", email, verifyCode);
        String result = null;
        if ("email".equals(verifyMethod)) {
            String emailMsg = "Forget password, verifyCode:" + verifyCode;
            adamSysEmailService.asyncSendEmail(email, emailMsg, "Forget password");
            result = email;
        } else if ("phone".equals(verifyMethod)) {
            String phoneMsg = "Forget password, verifyCode:" + verifyCode;
            String phoneNumber = adamUser.getPhoneNumber();
            adamSysMessageService.asyncSendMessage(phoneMsg, phoneNumber);
            result = "*******" + phoneNumber.substring(phoneNumber.length() - 4);
        }

        return AdamResultDto.success(result);
    }

    @Override
    public AdamResultDto forgetVerifyCodeConfirm(String email, String verifyCode, String newPw) {
        AdamUser adamUser = adamUserService.getUserByEmail(email);
        if (adamUser == null || StringUtils.isEmpty(verifyCode)) {
            return AdamResultDto.failure(AdamErrorCode.ADAM001_PARAM_ERROR);
        }

        String redisKey = AdamRedisConstants.USER_PASSWORD_FORGET_KEY + email;
        String redisValue = (String) redisUtil.get(redisKey);
        // 验证码过期
        if (redisValue == null) {
            return AdamResultDto.failure(AdamErrorCode.ADAM001_VERIFYCODE_EXPIRED);
        }
        // 验证码不正确
        if (!verifyCode.equals(redisValue)) {
            return AdamResultDto.failure(AdamErrorCode.ADAM001_VERIFYCODE_ERROR);
        }
        if (!StringUtils.isEmpty(newPw)) {
            // 密码格式错误
            AdamResultDto checkResult = this.checkPasswordFormat(newPw);
            if (!checkResult.isSuccess()) {
                return checkResult;
            }
            redisUtil.del(redisKey);
            String passwordErrorKey = AdamRedisConstants.USER_PASSWORD_ERROR_KEY + email;
            if (redisUtil.get(passwordErrorKey) != null) {
                redisUtil.del(passwordErrorKey);
            }
            AdamUser upUser = new AdamUser();
            upUser.setId(adamUser.getId());
            upUser.setPassword(getPasswordMD5(newPw));
            upUser.setUpdateTime(LocalDateTime.now());
            int i = adamUserService.updateById(upUser);
            return i > 0 ? AdamResultDto.success() : AdamResultDto.failure(AdamErrorCode.ADAM001_OPERATION_FAILED);
        }
        return AdamResultDto.success();
    }

}

