package com.njcn.product.auth.service.impl;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.njcn.common.config.GeneralInfo;
import com.njcn.common.pojo.constant.LogInfo;
import com.njcn.common.pojo.enums.common.DataStateEnum;
import com.njcn.common.pojo.enums.response.CommonResponseEnum;
import com.njcn.common.pojo.exception.BusinessException;
import com.njcn.common.utils.PubUtils;

import com.njcn.product.auth.pojo.dto.UserDTO;
import com.njcn.product.auth.pojo.enums.UserResponseEnum;
import com.njcn.product.auth.pojo.enums.UserStatusEnum;
import com.njcn.product.auth.mapper.UserMapper;
import com.njcn.product.auth.pojo.constant.UserState;

import com.njcn.product.auth.pojo.po.*;
import com.njcn.product.auth.pojo.vo.UserVO;
import com.njcn.product.auth.service.*;

import com.njcn.product.system.dept.pojo.po.Dept;
import com.njcn.web.utils.RequestUtil;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;


import javax.validation.constraints.NotNull;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.*;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author hongawen
 * @since 2021-12-13
 */
@Service
@RequiredArgsConstructor
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {



    private final IUserStrategyService userStrategyService;
    private final IRoleService roleService;
    private final IUserSetService userSetService;


    @Override
    public UserDTO getUserByName(String loginName) {
        User user = getUserByLoginName(loginName);
        if (Objects.isNull(user)) {
            return null;
        }
        List<String> roleNames = roleService.getRoleNameByUserId(user.getId());
        UserSet userSet = userSetService.lambdaQuery().eq(UserSet::getUserId, user.getId()).one();
        return new UserDTO(user.getId(), user.getLoginName(), user.getName(), user.getPassword(), roleNames, userSet.getSecretKey(), userSet.getStandBy(), user.getDeptId(), user.getType(), user.getHeadSculpture());
    }


    @Override
    public void judgeUserStatus(String loginName) {
        User user = getUserByLoginName(loginName);
        if (Objects.isNull(user)) {
            throw new BusinessException(UserResponseEnum.LOGIN_WRONG_PWD);
        }
        //超级管理员则不做任何逻辑判断
        if (user.getType() == 0) {
            //更新用户登录时间，以及错误登录记录的信息归零。
            user.setState(UserState.ENABLE);
            user.setLoginErrorTimes(0);
            user.setLoginTime(LocalDateTime.now());
            user.setFirstErrorTime(null);
            user.setLockTime(null);
            this.baseMapper.updateById(user);
            return;
        }
        //根据用户类型获取对应用户策略
        UserStrategy userStrategy = userStrategyService.lambdaQuery()
                .eq(UserStrategy::getType, user.getCasualUser())
                .eq(UserStrategy::getState, DataStateEnum.ENABLE.getCode())
                .one();
        switch (user.getState()) {
            case UserState.LOCKED:
                LocalDateTime lockTime = user.getLockTime();
                lockTime = lockTime.plusMinutes(userStrategy.getLockPwdTime());
                LocalDateTime nowTime = LocalDateTime.now();
                //判断是否满足锁定时间
                if (nowTime.isBefore(lockTime)) {
                    CommonResponseEnum testEnum = CommonResponseEnum.DYNAMIC_RESPONSE_ENUM;
                    testEnum.setMessage("账号已被锁定:锁定剩余时长" + ChronoUnit.MINUTES.between(nowTime, lockTime) + "分钟");
                    throw new BusinessException(testEnum);
                }
                break;
            case UserState.DELETE:
                //用户已注销
                throw new BusinessException(UserResponseEnum.LOGIN_USER_DELETE);
            case UserState.UNCHECK:
                //用户未审核
                throw new BusinessException(UserResponseEnum.LOGIN_USER_UNAUDITED);
            case UserState.SLEEP:
                //用户已休眠
                throw new BusinessException(UserResponseEnum.LOGIN_USER_SLEEP);
            case UserState.OVERDUE:
                //用户密码已过期
                throw new BusinessException(UserResponseEnum.LOGIN_USER_PASSWORD_EXPIRED);
            default:
                if (user.getPwdState() == 1) {
                    throw new BusinessException(UserResponseEnum.NEED_MODIFY_PWD);
                }
                //用户状态正常，判断其他细节
                judgeFirstLogin(user, userStrategy);
        }
        //所有验证通过后，更新用户登录时间，以及错误登录记录的信息归零。
        user.setState(UserState.ENABLE);
        user.setLoginErrorTimes(0);
        user.setLoginTime(LocalDateTime.now());
        user.setFirstErrorTime(null);
        user.setLockTime(null);
        this.baseMapper.updateById(user);
    }

    /**
     * 根据登录名查询用户
     *
     * @param loginName 登录名
     * @return 用户信息
     */
    private User getUserByLoginName(String loginName) {
        return lambdaQuery()
                .eq(User::getLoginName, loginName)
                .one();
    }
    /**
     * 判断是否需要修改密码
     */
    private void judgeFirstLogin(@NotNull User user, UserStrategy userStrategy) {
        if (user.getPwdState() == 1) {
            throw new BusinessException(UserResponseEnum.NEED_MODIFY_PWD);
        } else {
            judgeIp(user, userStrategy);
        }
    }

    /**
     * 判断用户是否在合理的IP内登录
     */
    private void judgeIp(@NotNull User user, UserStrategy userStrategy) {
        String ipSection = user.getLimitIpStart() + "-" + user.getLimitIpEnd();
        log.error("用户实际ip:" + RequestUtil.getRealIp());
        log.error("用户限制ip:" + ipSection);
        if (RequestUtil.getRealIp().equalsIgnoreCase(LogInfo.UNKNOWN_IP)) {
            //feign接口可能获取的IP是空的
            throw new BusinessException(UserResponseEnum.INVALID_IP);
        } else if (!PubUtils.ipExistsInRange(RequestUtil.getRealIp(), ipSection)) {
            throw new BusinessException(UserResponseEnum.INVALID_IP);
        } else {
            judgeLimitTime(user, userStrategy);
        }
        judgeLimitTime(user, userStrategy);
    }

    /**
     * 判断用户是否在允许的时间段内登录
     */
    private void judgeLimitTime(@NotNull User user, UserStrategy userStrategy) {
        int nowHour = Calendar.getInstance().get(Calendar.HOUR_OF_DAY);
        String[] limitTime = user.getLimitTime().split(StrUtil.DASHED);
        if (nowHour >= Integer.parseInt(limitTime[0]) && nowHour < Integer.parseInt(limitTime[1])) {
            judgePwdTimeValidity(user, userStrategy);
        } else {
            throw new BusinessException(UserResponseEnum.INVALID_TIME);
        }
    }

    /**
     * 判断用户密码是否已经过期
     */
    private void judgePwdTimeValidity(@NotNull User user, UserStrategy userStrategy) {
        LocalDateTime pwdValidity = user.getPwdValidity();
        pwdValidity = pwdValidity.plusMonths(userStrategy.getLimitPwdDate());
        if (LocalDateTime.now().isBefore(pwdValidity)) {
            judgeLeisurePwd(user, userStrategy);
        } else {
            //将用户状态置为过期
            user.setState(UserState.OVERDUE);
            this.baseMapper.updateById(user);
            throw new BusinessException(UserResponseEnum.LOGIN_USER_PASSWORD_EXPIRED);
        }

    }

    /**
     * 判断用户闲置
     */
    private void judgeLeisurePwd(@NotNull User user, UserStrategy userStrategy) {
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime sleepTime = user.getLoginTime().plusDays(userStrategy.getSleep());
        LocalDateTime logoutTime = user.getLoginTime().plusDays(userStrategy.getLogout());
        if (now.isAfter(sleepTime) && now.isBefore(logoutTime)) {
            //将用户状态置为休眠
            user.setState(UserState.SLEEP);
            this.baseMapper.updateById(user);
            throw new BusinessException(UserResponseEnum.LOGIN_USER_SLEEP);
        } else if (now.isAfter(logoutTime)) {
            //将用户状态置为注销
            user.setState(UserState.DELETE);
            this.baseMapper.updateById(user);
            throw new BusinessException(UserResponseEnum.LOGIN_USER_DELETE);
        }
    }
    @Override
    public UserDTO loadUserByPhone(String phone) {
        User user = getUserByPhone(phone, false, null);
        if (Objects.isNull(user)) {
            return null;
        }
        List<String> roleNames = roleService.getRoleNameByUserId(user.getId());
        UserSet userSet = userSetService.lambdaQuery().eq(UserSet::getUserId, user.getId()).one();
        return new UserDTO(user.getId(), user.getLoginName(), user.getName(), user.getPassword(), roleNames, userSet.getSecretKey(), userSet.getStandBy(), user.getDeptId(), user.getType(), user.getHeadSculpture());
    }

    @Override
    public UserVO getUserById(String id) {
        UserVO userVO = new UserVO();
        User user = lambdaQuery().eq(User::getId, id).one();
        if (Objects.isNull(user)) {
            return null;
        }
        BeanUtil.copyProperties(user, userVO);

        return userVO;
    }

    @Override
    public List<User> simpleList(Boolean allUserFlag) {
        LambdaQueryWrapper<User> userLambdaQueryWrapper = new LambdaQueryWrapper<>();
        userLambdaQueryWrapper.select(User::getId, User::getName,User::getLoginName).eq(User::getState, DataStateEnum.ENABLE.getCode());
        if(!allUserFlag){
            userLambdaQueryWrapper.eq(User::getType,2);
        }
        return this.baseMapper.selectList(userLambdaQueryWrapper);
    }


    /**
     * 根据手机号查询用户
     *
     * @param phone 手机号码
     * @return 用户信息
     */
    private User getUserByPhone(String phone, boolean result, String id) {
        if (result) {
            return lambdaQuery()
                    .eq(User::getPhone, phone)
                    .ne(User::getId, id)
                    .one();
        } else {
            return lambdaQuery()
                    .eq(User::getPhone, phone)
                    .one();
        }
    }

    @Override
    public String updateUserLoginErrorTimes(String loginName) {
        User user = this.lambdaQuery().eq(User::getLoginName, loginName).one();
        LocalDateTime now = LocalDateTime.now();
        if (Objects.nonNull(user)) {
            UserStrategy userStrategy = userStrategyService.getUserStrategy(user.getCasualUser());
            Integer loginErrorTimes = user.getLoginErrorTimes();
            ++loginErrorTimes;
            if (Objects.isNull(user.getFirstErrorTime())) {
                //首次错误，错误1次、记录第一次错误时间
                user.setLoginErrorTimes(loginErrorTimes);
                user.setFirstErrorTime(LocalDateTime.now());
            } else if (loginErrorTimes <= userStrategy.getLimitPwdTimes()) {
                //如果次数在策略之内，还未被锁定
                LocalDateTime firstErrorTime = user.getFirstErrorTime();
                firstErrorTime = firstErrorTime.plusMinutes(userStrategy.getLockPwdCheck());
                if (now.isAfter(firstErrorTime)) {
                    //重置密码错误次数、时间等记录
                    user.setLoginErrorTimes(1);
                    user.setFirstErrorTime(LocalDateTime.now());
                } else {
                    user.setLoginErrorTimes(loginErrorTimes);
                }
            } else {
                user.setLockTime(LocalDateTime.now());
                user.setState(UserStatusEnum.LOCKED.getCode());
                user.setLoginErrorTimes(loginErrorTimes);
                this.baseMapper.updateById(user);
                return UserResponseEnum.LOGIN_USER_LOCKED.getMessage();
            }
            this.baseMapper.updateById(user);
        }
        return CommonResponseEnum.SUCCESS.getMessage();
    }


}
