package com.cnooc.expert.auth.service.impl;

import cn.hutool.core.lang.Validator;
import cn.hutool.core.util.IdcardUtil;
import com.cnooc.expert.auth.service.AccountLockService;
import com.cnooc.expert.common.constant.TokenConstants;
import com.cnooc.expert.common.exception.BusinessException;
import com.cnooc.expert.common.exception.GlobalErrorCodeConstants;
import com.cnooc.expert.common.utils.JwtUtils;
import com.cnooc.expert.common.utils.Sm2Util;
import com.cnooc.expert.common.utils.UserUtils;
import com.cnooc.expert.common.utils.ValidUtils;
import com.cnooc.expert.external.expert.auth.service.LoginServicesClient;
import com.cnooc.expert.external.expert.model.response.ExpertInfoAppResp;
import com.cnooc.expert.external.expert.model.response.ExpertInfoResp;
import com.cnooc.expert.system.entity.pojo.ZhuanJiaUser;
import com.cnooc.expert.system.entity.vo.LoginVO;
import com.cnooc.expert.system.entity.vo.VerifyCodeVO;
import com.cnooc.expert.auth.service.LoginService;
import com.cnooc.expert.auth.service.SmsService;
import com.cnooc.expert.auth.service.SysCaptchaService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.security.crypto.password.PasswordEncoder;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @Author: songYuHang
 * @CreateTime: 2025-09-18  15:23
 */
@Service
@Slf4j
public class LoginServiceImpl implements LoginService {

    @Resource(name="redisCommonTemplate")
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private SmsService smsService;

    @Autowired
    private AccountLockService accountLockService;

    @Autowired
    private SysCaptchaService sysCaptchaService;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private LoginServicesClient loginServicesClient;

    /** 身份证密码登录 */
    private static final int ID_NUMBER_PASSWORD = 1;
    /** 手机验证码登录 */
    private static final int PHONE_CODE = 2;

    /**
     * 登录逻辑
     * @param loginVO 登录
     * @return Result<String> token
     */
    @Override
    public String login(LoginVO loginVO) {
        log.info("开始执行登录逻辑");
        ValidUtils.isNotNull(loginVO.getLoginType(), GlobalErrorCodeConstants.PARAM_REQUIRED);
        String token;
        switch (loginVO.getLoginType()) {
            case ID_NUMBER_PASSWORD:
                token = idNumberLogin(loginVO);
                break;
            case PHONE_CODE:
                token = phoneCodeLogin(loginVO);
                break;
            default:
                throw new BusinessException("请选择登录类型");
        }
        return token;
    }

    /**
     * 获取验证码逻辑
     * @param vo 手机号等信息
     * @return Result<String> token
     */
    @Override
    public String sendPhoneCode(LoginVO vo) {
        log.info("开始执行获取验证码逻辑");
        ValidUtils.isText(vo.getPhoneNumber(), "请输入手机号");
        ValidUtils.isTrue(Validator.isMobile(vo.getPhoneNumber()), "请输入正确的手机号");

        //待确认，验证码下发是调用第三方平台吗
        //return Result.success("验证码已发送");
/*        boolean flag = sysCaptchaService.validate(vo.getKey(), vo.getCaptcha());
        if(!flag){
            throw new BusinessException(GlobalErrorCodeConstants.CAPTCHA_EXPIRED.getCode(),GlobalErrorCodeConstants.CAPTCHA_EXPIRED.getMsg());
        }else{*/
            boolean smsfalg = smsService.sendSmsCode(vo.getPhoneNumber());
            if(!smsfalg) {
                throw new BusinessException(GlobalErrorCodeConstants.SEND_SMS_ERROR.getCode(),GlobalErrorCodeConstants.SEND_SMS_ERROR.getMsg());
            } else {
                return "短信验证码发送成功";
            }
        //}
    }

    @Override
    public String changePass(LoginVO loginVO) {
        log.info("开始执行修改密码逻辑");
        ValidUtils.isText(loginVO.getPhoneNumber(), "请输入手机号");
        ValidUtils.isText(loginVO.getPhoneCode(), "请输入验证码");
        ValidUtils.isTrue(Validator.isMobile(loginVO.getPhoneNumber()), "请输入正确格式的手机号");
        ValidUtils.isText(loginVO.getPassword(), "请输入密码");
        ValidUtils.isValidPassword(loginVO.getPassword(),GlobalErrorCodeConstants.PARAM_PASSWORD_FORMAT_ERROR);
        //1.根据手机号去库中查询是否存在
        ExpertInfoResp expertInfoResp = loginServicesClient.querySingleByShengFenZhengOrMobile(loginVO.getPhoneNumber(),null);
        if(expertInfoResp == null){
            throw new BusinessException(GlobalErrorCodeConstants.USER_NOT_EXISTS.getCode(),GlobalErrorCodeConstants.USER_NOT_EXISTS.getMsg());
        }
        //2.判断密码是否存在
        ExpertInfoAppResp expertInfoAppResp = loginServicesClient.getZhuanJiaInfoAppById(expertInfoResp.getZhuanJiaGuid());
        String pwd = Sm2Util.decrypt(loginVO.getPassword());
        if(expertInfoAppResp == null){
            //没有记录的话就是新建记录
            loginServicesClient.saveZhuanJiaInfoApp(null,passwordEncoder.encode(pwd));
        }else{
            //否则更新密码
            loginServicesClient.updateZhuanJiaInfoApp(expertInfoAppResp.getBaseGuid(),passwordEncoder.encode(pwd));
        }
        //手机号，验证码，图形验证码都需要判断
        //判断密码是否符合规则
        //进行解密处理
        //调用数据库更新密码
        return "密码重置成功";
    }

    @Override
    public String verifyCode(VerifyCodeVO codeVO) {
        log.info("手机验证码验证逻辑");
        ValidUtils.isText(codeVO.getPhoneNumber(), "请输入手机号");
        ValidUtils.isText(codeVO.getPhoneCode(), "请输入验证码");
        ValidUtils.isTrue(Validator.isMobile(codeVO.getPhoneNumber()), "请输入正确格式的手机号");
        boolean smsfalg = smsService.verifySmsCode(codeVO.getPhoneNumber(),codeVO.getPhoneCode());
        if(!smsfalg){
            throw new BusinessException(GlobalErrorCodeConstants.CAPTCHA_EXPIRED.getCode(),GlobalErrorCodeConstants.CAPTCHA_EXPIRED.getMsg());
        }else{
            return "短信验证码验证成功";
        }
    }


    /**
     * 身份证密码登录
     * @param loginVO 登录参数
     * @return  token
     */
    private String idNumberLogin(LoginVO loginVO) {
        log.info("开始执行身份证登录逻辑");
        ValidUtils.isText(loginVO.getIdNumber(), "请输入身份证号");
        ValidUtils.isText(loginVO.getPassword(), "请输入密码");
        ValidUtils.isTrue(IdcardUtil.isValidCard(loginVO.getIdNumber()), "请输入正确的身份证号");
        ValidUtils.isValidPassword(loginVO.getPassword(),GlobalErrorCodeConstants.PARAM_PASSWORD_FORMAT_ERROR);
        ExpertInfoResp expertInfoResp = loginServicesClient.querySingleByShengFenZhengOrMobile(null,loginVO.getIdNumber());
        if(expertInfoResp == null){
            throw new BusinessException(GlobalErrorCodeConstants.USER_NOT_EXISTS.getCode(),GlobalErrorCodeConstants.USER_NOT_EXISTS.getMsg());
        }
        boolean isAccountLocked = accountLockService.isAccountLocked(expertInfoResp.getZhuanJiaGuid());
        if(isAccountLocked){
            //如果账号锁定了，返回错误信息
            Map<String, Object> errorData = new HashMap<>();
            errorData.put("dueDate", accountLockService.getLockRemainingTime(expertInfoResp.getZhuanJiaGuid()));
            throw new BusinessException(GlobalErrorCodeConstants.USER_LOCKED.getCode(),GlobalErrorCodeConstants.USER_LOCKED.getMsg(), "user_login", errorData);
        }
        ExpertInfoAppResp expertInfoAppResp = loginServicesClient.getZhuanJiaInfoAppById(expertInfoResp.getZhuanJiaGuid());
        if(expertInfoAppResp == null){
            throw new BusinessException(GlobalErrorCodeConstants.PASSWORD_NOT_EXIST.getCode(),GlobalErrorCodeConstants.PASSWORD_NOT_EXIST.getMsg());
        }
        // 验证码效验
/*        boolean flag = sysCaptchaService.validate(loginVO.getKey(), loginVO.getCaptcha());
        if (!flag) {
            throw new BusinessException(GlobalErrorCodeConstants.CAPTCHA_EXPIRED.getCode(),GlobalErrorCodeConstants.CAPTCHA_EXPIRED.getMsg());
        }*/
        //1.需要去库中查询，是否存在
        //2.存在校验密码
        //解密
        String pwd = Sm2Util.decrypt(loginVO.getPassword());
        boolean flag = passwordEncoder.matches(pwd, expertInfoAppResp.getPassword());
        if (!flag) {
            // 登录日志
            accountLockService.handleLoginFailure(expertInfoResp.getZhuanJiaGuid());
            throw new BusinessException(GlobalErrorCodeConstants.PASSWORD_ERROR.getCode(),GlobalErrorCodeConstants.PASSWORD_ERROR.getMsg());
        }

        //3.生成相应的uuid作为redis的key
        String uuidKey = UUID.randomUUID().toString();

        ZhuanJiaUser zhuanJiaUser = convert2ZhuanjiaUser( expertInfoResp );
        redisTemplate.opsForValue().set(TokenConstants.LOGIN_USER_KEY_ + expertInfoResp.getZhuanJiaGuid(), zhuanJiaUser, 48, TimeUnit.HOURS);
        UserUtils.setUserId(zhuanJiaUser);
        String token = JwtUtils.createToken(expertInfoResp.getZhuanJiaGuid(),uuidKey);
        //6.返回token
        accountLockService.handleLoginSuccess(expertInfoResp.getZhuanJiaGuid());
        return token;
    }

    /**
     * 手机验证码登录
     * @param loginVO 手机号登录参数
     * @return  token
     */
    private String phoneCodeLogin(LoginVO loginVO) {
        log.info("开始执行手机验证码登录逻辑");
        ValidUtils.isText(loginVO.getPhoneNumber(), "请输入手机号");
        ValidUtils.isText(loginVO.getPhoneCode(), "请输入验证码");
        ValidUtils.isTrue(Validator.isMobile(loginVO.getPhoneNumber()), "请输入正确格式的手机号");
        //1.根据手机号去库中查询是否存在
        ExpertInfoResp expertInfoResp = loginServicesClient.querySingleByShengFenZhengOrMobile(loginVO.getPhoneNumber(),null);
        if(expertInfoResp == null){
            throw new BusinessException(GlobalErrorCodeConstants.USER_NOT_EXISTS.getCode(),GlobalErrorCodeConstants.USER_NOT_EXISTS.getMsg());
        }
        //expertInfoResp = new ExpertInfoResp();
        //expertInfoResp.setZhuanJiaGuid("1234");
        boolean isAccountLocked = accountLockService.isAccountLocked(expertInfoResp.getZhuanJiaGuid());
        if(isAccountLocked){
            //如果账号锁定了，返回错误信息
            Map<String, Object> errorData = new HashMap<>();
            errorData.put("dueDate", accountLockService.getLockRemainingTime(expertInfoResp.getZhuanJiaGuid()));
            throw new BusinessException(GlobalErrorCodeConstants.USER_LOCKED.getCode(),GlobalErrorCodeConstants.USER_LOCKED.getMsg(), "user_login", errorData);
        }
        //2.存在校验验证码
        if (!smsService.verifySmsCode(loginVO.getPhoneNumber(), loginVO.getPhoneCode())) {
            //登录日志
            accountLockService.handleLoginFailure(expertInfoResp.getZhuanJiaGuid());
            throw new BusinessException(GlobalErrorCodeConstants.CAPTCHA_EXPIRED.getCode(),GlobalErrorCodeConstants.CAPTCHA_EXPIRED.getMsg());
        }
        //3.生成相应的uuid作为redis的key
        String uuidKey = UUID.randomUUID().toString();
        ZhuanJiaUser zhuanJiaUser = convert2ZhuanjiaUser( expertInfoResp );
        redisTemplate.opsForValue().set(TokenConstants.LOGIN_USER_KEY_ + expertInfoResp.getZhuanJiaGuid(), zhuanJiaUser, 48, TimeUnit.HOURS);
        UserUtils.setUserId(zhuanJiaUser);
        String token = JwtUtils.createToken(expertInfoResp.getZhuanJiaGuid(),uuidKey);
        accountLockService.handleLoginSuccess(expertInfoResp.getZhuanJiaGuid());
        return token;
    }

      private ZhuanJiaUser convert2ZhuanjiaUser(ExpertInfoResp expertInfoResp){
          if( expertInfoResp == null ){
              return null;
          }

          ZhuanJiaUser zhuanJiaUser = new ZhuanJiaUser();
          zhuanJiaUser.setZhuanJiaGuid(expertInfoResp.getZhuanJiaGuid());
          zhuanJiaUser.setMobile(expertInfoResp.getMobile());
          zhuanJiaUser.setShenFenZheng(expertInfoResp.getShenFenZheng());
          zhuanJiaUser.setShiFouYiFaZhuanJia(expertInfoResp.getShiFouYiFaZhuanJia());
          zhuanJiaUser.setZhuanJiaCode(expertInfoResp.getZhuanJiaCode());
          zhuanJiaUser.setSuoShuBuMeng(expertInfoResp.getSuoShuBuMeng());
          zhuanJiaUser.setZhuanJiaName(expertInfoResp.getZhuanJiaName());
          zhuanJiaUser.setZhuanJiaShiXiangGuid(expertInfoResp.getZhuanJiaShiXiangGuid());
          zhuanJiaUser.setZhuanJiaZhuangTai(expertInfoResp.getZhuanJiaZhuangTai());
          zhuanJiaUser.setAdAccount(expertInfoResp.getAdAccount());

          return zhuanJiaUser;
      }

      @Override
      public ZhuanJiaUser getZhuanJiaUserByToken(String token){
          try {
              Map<String, String> userMap = JwtUtils.getTokenInfo(token);
              String userId = userMap.get(TokenConstants.USER_ID);
              ZhuanJiaUser zhuanjiaUser = (ZhuanJiaUser)redisTemplate.opsForValue().get(TokenConstants.LOGIN_USER_KEY_ + userId);
              if(zhuanjiaUser!=null) {
                  UserUtils.setUserId(zhuanjiaUser);
              }
              return zhuanjiaUser;
          } catch (Exception e) {
              log.info("token解析异常 {}",e.getMessage(),e);
              return null;
          }
      }
}
