package cn.estsh.i3plus.core.apiservice.serviceimpl.base;

import cn.estsh.i3plus.core.api.iservice.base.ISystemLoginService;
import cn.estsh.i3plus.platform.common.tool.EncryptTool;
import cn.estsh.i3plus.platform.common.util.CommonConstWords;
import cn.estsh.i3plus.pojo.base.enumutil.CommonEnumUtil;
import cn.estsh.i3plus.pojo.base.shirotoken.AdminToken;
import cn.estsh.i3plus.pojo.base.shirotoken.SaAdminToken;
import cn.estsh.i3plus.pojo.base.shirotoken.UserToken;
import cn.estsh.i3plus.pojo.platform.bean.SessionUser;
import cn.estsh.i3plus.pojo.platform.bean.SysUser;
import cn.estsh.i3plus.pojo.platform.repository.SysUserRepository;
import cn.estsh.impp.framework.boot.auth.AuthUtil;
import cn.estsh.impp.framework.boot.util.ImppRedis;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authc.CredentialsException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

/**
 * @Description : 用户登陆方法
 * @Reference :
 * @Author : alwaysfrin
 * @CreateDate : 2018-10-13 17:18
 * @Modify:
 **/
@Service
public class SystemLoginService implements ISystemLoginService {
    private static final Logger LOGGER = LoggerFactory.getLogger(SystemLoginService.class);

    @Autowired
    private SysUserRepository sysUserRDao;

    /**
     * 核心的缓存
     */
    @Resource(name="redisCore")
    protected ImppRedis redisCore;

    @Override
    @ApiOperation(value = "用户登录",notes = "普通用户登录")
    public SessionUser queryUserLogin(String loginName, String loginPwd, String languageCode) {
        //生成令牌
        UserToken ut = new UserToken(loginName,loginPwd,languageCode);
        //token验证
        return AuthUtil.login(ut);
    }

    @Override
    @ApiOperation(value = "用户登录",notes = "管理用户登录")
    public SessionUser queryAdminLogin(String loginName, String loginPwd, String languageCode) {
        //生成令牌
        AdminToken adminToken = new AdminToken(loginName,loginPwd,languageCode);
        //token验证
        return AuthUtil.login(adminToken);
    }

    @Override
    @ApiOperation(value = "封装用户",notes = "封装普通用户信息")
    public SessionUser queryCheckUserLogin(UserToken userToken) {
        //验证用户
        SysUser user = getUserLoginInfo(userToken.getLoginName(),userToken.getLoginPwd());
        LOGGER.info("【验证用户checkUserLogin】{}",user);
        //未抛异常，封装用户
        return packSessionUser(user,CommonEnumUtil.USER_TYPE.USER.getCode(),userToken.getLanguageCode());
    }

    @Override
    @ApiOperation(value = "封装用户",notes = "封装管理员信息")
    public SessionUser queryCheckAdminLogin(AdminToken adminToken) {
        //验证用户
        SysUser user = getUserLoginInfo(adminToken.getLoginName(),adminToken.getLoginPwd());
        //未抛异常，封装用户
        return packSessionUser(user,CommonEnumUtil.USER_TYPE.ADMIN.getCode(),adminToken.getLanguageCode());
    }

    @Override
    @ApiOperation(value = "封装用户",notes = "封装超级管理员信息")
    public SessionUser queryCheckSaAdminLogin(SaAdminToken saAdminToken) {
        //SysUser user = getUserLoginInfo(saAdminToken.getLoginName(),saAdminToken.getLoginPwd());
        SysUser user = null;
        /**
         * to do
         *
         * 此处外网获取sa超级管理员用户名密码
         * 或者导入加密证书生成内存超级管理员用户名密码
         */
        return packSessionUser(user,CommonEnumUtil.USER_TYPE.SA.getCode(),saAdminToken.getLanguageCode());
    }

    @Override
    @ApiOperation(value = "登录密码错误",notes = "登录密码错误记录错误次数功能")
    public Integer doLoginPasswordError(String loginName,String sessionId) {
        SysUser user = sysUserRDao.getByProperty(new String[]{"userLoginName", "isValid"},
                new Object[]{loginName, CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue()});
        if(user != null){
            String redisKey = CommonConstWords.USER_LOGIN_ERROR + "_" + sessionId + "_" + user.getId();
            Object redisValue = redisCore.getObject(redisKey);
            Integer num = redisValue == null ? 1 : Integer.parseInt(redisValue.toString()) + 1;

            if(num >= CommonConstWords.USER_LOGIN_ERROR_MAX_NUM){
                user.setUserStatus(CommonEnumUtil.USER_STATUS.LOCKING.getValue());
                redisCore.deleteKey(redisKey);
                sysUserRDao.update(user);
            }else{
                redisCore.putObject(redisKey,num,CommonConstWords.REDIS_TIME_DAY_ONE);
            }
            return num;
        }
        return 0;
    }

    /**
     * 根据用户名密码查询用户
     * @param loginName
     * @param pwd
     * @return
     */
    public SysUser getUserLoginInfo(String loginName,String pwd) {
        SysUser user = sysUserRDao.getByProperty(
                            new String[]{"userLoginName","isValid"},
                            new Object[]{loginName,CommonEnumUtil.IS_VAILD.VAILD.getValue()}
                            );
        if(user == null){    //用户不存在
            throw new CredentialsException("用户不存在");
        }else {
            if(user.getUserStatus() != CommonEnumUtil.USER_STATUS.ENABLE.getValue()){
                throw new LockedAccountException("账号已被锁定");
            }
            try {
                // 密码加密
                pwd = EncryptTool.hexMD5(pwd);
            } catch (Exception e) {
                LOGGER.error("登录密码加密出错。");
                throw new IncorrectCredentialsException("登陆密码错误");
            }
            if (!StringUtils.equals(user.getUserLoginPassword(), pwd)) {    //密码不符
                LOGGER.error("密码验证错误。");
                throw new IncorrectCredentialsException("登陆密码错误");
            }

            return user;
        }
    }

    /**
     * 封装用户登陆信息
     * @param user
     * @param userType
     * @param languageCode
     * @return
     */
    private SessionUser packSessionUser(SysUser user,String userType, String languageCode) {
        SessionUser sessionUser = new SessionUser();
        sessionUser.setLanguageCode(languageCode);
//        sessionUser.setSiteCode(user.getFactoryCode());
        sessionUser.setUserName(user.getUserName());
        sessionUser.setUserType(userType);
//        sessionUser.setUserCode(user.getUserInfo().getLanguageCode());

        return sessionUser;
    }


}
