package com.sdtool.business.service;

import com.sdtool.business.dao.SystemDao;
import com.sdtool.common.api.DeptService;
import com.sdtool.common.api.LoginUserService;
import com.sdtool.common.api.NoSqlKeysService;
import com.sdtool.common.api.RoleService;
import com.sdtool.common.base.BaseService;
import com.sdtool.common.datas.RedisKeys;
import com.sdtool.common.entity.site.ERPTokenUser;
import com.sdtool.common.entity.system.LoginUser;
import com.sdtool.common.entity.system.UserRole;
import com.sdtool.common.tool.ShareCodeUtils;
import com.dySweetFishPlugin.redis.RedisService;
import com.dySweetFishPlugin.sql.TableIdService;
import com.dySweetFishPlugin.sql.dao.TunaService;
import com.dySweetFishPlugin.tool.crypto.EncryptUtil;
import com.sweetfish.convert.json.JsonConvert;
import com.sweetfish.service.Local;
import com.sweetfish.service.RetResult;
import com.sweetfish.source.PageFlipper;
import com.sweetfish.util.AnyValue;
import com.sweetfish.util.AutoLoad;
import com.sweetfish.util.ResourceType;
import org.apache.commons.lang3.StringUtils;
import org.rex.RMap;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

@AutoLoad(false)
@Local
@ResourceType(LoginUserService.class)
public class LoginUserServiceImpl extends BaseService implements LoginUserService {

    @Resource
    RedisService redisService;

    @Resource
    NoSqlKeysService keysService;

    @Resource
    JsonConvert jsonConvert;

    @Resource
    TableIdService tableIdService;

    @Resource
    DeptService deptService;

    @Resource
    RoleService roleService;

    @Resource
    TunaService tunaService;

    /**
     * 密码盐
     */
    @Resource(name = "property.passwordSalt")
    private String passwordSalt;

    private SystemDao systemDao;

    @Override
    public void init(AnyValue config) {
        super.init(config);
    }

    @Override
    public void destroy(AnyValue config) {
        super.destroy(config);
    }

    @Override
    public void start(AnyValue config) {
        systemDao = tunaService.generate(SystemDao.class);
    }

    //region 人员档案

    /**
     * 从redis中获取人员档案，用于简单数据交互
     *
     * @param userId       用户id
     * @param supplierCode 分表
     * @return 用户信息
     */
    public LoginUser getRedisLoginUser(long userId, long supplierCode) {
        return getRedisDocInfo(keysService.getRedisKey(RedisKeys.KEY_ERP_LOGINUSER, supplierCode), String.valueOf(userId), LoginUser.class);
    }

    public List<LoginUser> getRedisLoginUserList(String[] userIds, long supplierCode) {
        return getRedisDocInfos(LoginUser.class, keysService.getRedisKey(RedisKeys.KEY_ERP_LOGINUSER, supplierCode), userIds);
    }

    /**
     * 获取登录人员姓名
     *
     * @param userId       用户id
     * @param supplierCode 分表
     * @return 用户姓名
     */
    public String getRedisLoginUserName(long userId, long supplierCode) {
        LoginUser loginUser = getRedisLoginUser(userId, supplierCode);
        if (loginUser == null) {
            return "";
        }
        return loginUser.getUserName();
    }

    /**
     * 获取登录人的部门名称
     *
     * @param userId       用户id
     * @param supplierCode 分表
     * @return 部门名称
     */
    public String getRedisLoginUserDeptName(long userId, long supplierCode) {
        LoginUser loginUser = getRedisLoginUser(userId, supplierCode);
        if (loginUser == null) {
            return "";
        }
        return deptService.getRedisDeptName(loginUser.getDeptId(), supplierCode);
    }

    @SuppressWarnings({"rawtypes", "unchecked"})
    public RetResult<List<LoginUser>> getLoginUserList(RMap searchData, PageFlipper pageFlipper, String dataSourceId, long supplierCode) {
        RMap params = new RMap();
        if (searchData != null) {
            params.putAll(searchData);
        }

        if (!params.containsKey("status")) {
            params.put("status", -1);
        }

        if (!params.containsKey("deptId")) {
            params.put("deptId", -1);
        }

        List<LoginUser> userList = systemDao.queryLoginUsers(params, pageFlipper, dataSourceId, supplierCode);

        userList.forEach((x) -> x.setDeptName(deptService.getRedisDeptName(x.getDeptId(), supplierCode)));

        return RetResult.<List<LoginUser>>successT().retcode(0).result(userList).page(pageFlipper);
    }

    /**
     * 从数据库中获取用户信息，用于人员档案的修改
     *
     * @param userId       用户id
     * @param dataSourceId 分库
     * @param supplierCode 分表
     * @return 用户信息
     */
    @Override
    @SuppressWarnings({"rawtypes", "unchecked"})
    public RetResult<LoginUser> getLoginUserInfo(long userId, String dataSourceId, long supplierCode) {
        RMap parm = new RMap();
        parm.put("id", userId);
        LoginUser userInfo = systemDao.getUserInfo(parm, dataSourceId, supplierCode);
        userInfo.setDeptName(deptService.getRedisDeptName(userInfo.getDeptId(), supplierCode));
        List<UserRole> userRoles = roleService.getUserRoleList(userId, dataSourceId, supplierCode);
        userInfo.setRoleList(userRoles);
        String sRoleid = userRoles.stream().map((x) -> String.valueOf(x.getRoleId())).collect(Collectors.joining(","));
        userInfo.setRoleIds(sRoleid);
        return RetResult.<LoginUser>successT().result(userInfo);
    }

    @SuppressWarnings({"unchecked", "rawtypes"})
    private int accountExists(String loginName, String dataSourceId, long supplierCode) {
        //先查redis
        if (redisService.exists(keysService.getRedisKey(RedisKeys.KEY_ACCOUNT_ERP_CHECK, supplierCode, true) + loginName)) {
            return 1;
        }

        //查询数据库
        RMap paramMap = new RMap();
        paramMap.put("loginName", loginName);
        long count = systemDao.accountExists(paramMap, dataSourceId, supplierCode);
        if (count > 0L) {
            //如果账号存在，则在redis里面存储5分钟
            redisService.setex(keysService.getRedisKey(RedisKeys.KEY_ACCOUNT_ERP_CHECK, supplierCode, true) + loginName, 5 * 60, loginName);
            return 1;
        } else {
            return 0;
        }
    }

    @Override
    public RetResult<Integer> checkAccount(String loginName, String dataSourceId, long supplierCode) {
        int iExists = accountExists(loginName, dataSourceId, supplierCode);

        if (iExists == -1) {
            return RetResult.<Integer>errorT().retinfo("账号查询出错");
        }
        return RetResult.<Integer>successT().result(iExists);
    }

    private List<UserRole> convertUserRole(long userId, String roleIds) {
        if (StringUtils.isEmpty(roleIds)) {
            return new ArrayList<>();
        }

        String[] roleIdArray = roleIds.split(",");
        return Arrays.stream(roleIdArray).map((x) -> {
            UserRole userRole = new UserRole();
            userRole.setUserId(userId);
            userRole.setRoleId(Long.parseLong(x));
            return userRole;
        }).collect(Collectors.toList());
    }

    @Override
    public RetResult<LoginUser> addLoginUser(LoginUser userInfo, ERPTokenUser currentUser, String dataSourceId, long supplierCode) {
        if (StringUtils.isBlank(userInfo.getLoginName())) {
            return RetResult.<LoginUser>errorT().retinfo("登录名不能为空");
        }

        if (StringUtils.isBlank(userInfo.getUserName())) {
            return RetResult.<LoginUser>errorT().retinfo("用户名不能为空");
        }

        //检查登录名重复
        if (accountExists(userInfo.getLoginName(), dataSourceId, supplierCode) == 1) {
            return RetResult.<LoginUser>errorT().retinfo("登录名已存在");
        }

        userInfo.setId(tableIdService.getTableIdMulti("tbUser.id", 1, dataSourceId, String.valueOf(supplierCode)));
        String userCode = deptService.getRedisDeptCode(userInfo.getDeptId(), supplierCode) +
                tableIdService.getTableCodeMulti("tbUser.Code", dataSourceId, String.valueOf(supplierCode));
        userInfo.setUserCode(userCode);
        userInfo.setShareCode(ShareCodeUtils.idToCode(userInfo.getId()));
        userInfo.setStatus(0);

        //默认密码
        if (StringUtils.isEmpty(userInfo.getPassword())) {
            userInfo.setPassword("123456");
        }
        userInfo.setPassword(EncryptUtil.md5Digest(userInfo.getPassword() + passwordSalt));

        userInfo.setAvatar("");
        userInfo.setRemark("");
        userInfo.setSalt("");

        userInfo.setDeptName(deptService.getRedisDeptName(userInfo.getDeptId(), supplierCode));

        LoginUser.create(userInfo, currentUser.getId());

        //配置用户角色信息
        List<UserRole> userRoleList = convertUserRole(userInfo.getId(), userInfo.getRoleIds());
        //覆盖用户角色在redis中的菜单
        roleService.writeRedisUserRole(userInfo.getId(), userRoleList, supplierCode);

        redisService.hset(keysService.getRedisKey(RedisKeys.KEY_ERP_LOGINUSER, supplierCode), String.valueOf(userInfo.getId()), userInfo);
        systemDao.addLoginUser(userInfo, userRoleList, dataSourceId, supplierCode);

        return RetResult.successT();
    }

    @Override
    public RetResult<LoginUser> addOnlyLoginUserInfo(LoginUser userInfo, ERPTokenUser currentUser, String dataSourceId, long supplierCode) {
        if (StringUtils.isBlank(userInfo.getLoginName())) {
            return RetResult.<LoginUser>errorT().retinfo("登录名不能为空");
        }

        if (StringUtils.isBlank(userInfo.getUserName())) {
            return RetResult.<LoginUser>errorT().retinfo("用户名不能为空");
        }

        //检查登录名重复
        if (accountExists(userInfo.getLoginName(), dataSourceId, supplierCode) == 1) {
            return RetResult.<LoginUser>errorT().retinfo("登录名已存在");
        }

        userInfo.setId(tableIdService.getTableIdMulti("tbUser.id", 1, dataSourceId, String.valueOf(supplierCode)));
        String userCode = deptService.getRedisDeptCode(userInfo.getDeptId(), supplierCode) +
                tableIdService.getTableCodeMulti("tbUser.Code", dataSourceId, String.valueOf(supplierCode));
        userInfo.setUserCode(userCode);
        userInfo.setShareCode(ShareCodeUtils.idToCode(userInfo.getId()));
        userInfo.setStatus(0);

        //默认密码
        if (StringUtils.isEmpty(userInfo.getPassword())) {
            userInfo.setPassword("123456");
        }
        userInfo.setPassword(EncryptUtil.md5Digest(userInfo.getPassword() + passwordSalt));

        userInfo.setAvatar("");
        userInfo.setRemark("");
        userInfo.setSalt("");
        userInfo.setRoleIds("");

        userInfo.setDeptName(deptService.getRedisDeptName(userInfo.getDeptId(), supplierCode));

        LoginUser.create(userInfo, currentUser.getId());

        redisService.hset(keysService.getRedisKey(RedisKeys.KEY_ERP_LOGINUSER, supplierCode), String.valueOf(userInfo.getId()), userInfo);
        systemDao.addLoginUser2(userInfo, dataSourceId, supplierCode);

        return RetResult.successT();
    }

    @Override
    @SuppressWarnings({"rawtypes", "unchecked"})
    public RetResult<LoginUser> updateLoginUser(LoginUser userInfo, ERPTokenUser currentUser, String dataSourceId, long supplierCode) {
        if (StringUtils.isBlank(userInfo.getUserName())) {
            return RetResult.<LoginUser>errorT().retinfo("用户名不能为空");
        }

        LoginUser.update(userInfo, currentUser.getId());

        RMap params = new RMap();
        params.put("userId", userInfo.getId());

        //配置用户角色信息
        List<UserRole> userRoleList = convertUserRole(userInfo.getId(), userInfo.getRoleIds());
        //覆盖用户角色在redis中的菜单
        roleService.writeRedisUserRole(userInfo.getId(), userRoleList, supplierCode);

        userInfo.setDeptName(deptService.getRedisDeptName(userInfo.getDeptId(), supplierCode));

        redisService.hset(keysService.getRedisKey(RedisKeys.KEY_ERP_LOGINUSER, supplierCode), String.valueOf(userInfo.getId()), userInfo);
        systemDao.updateLoginUser(userInfo, params, userRoleList, dataSourceId, supplierCode);

        return RetResult.successT();
    }

    @Override
    public RetResult<LoginUser> updateOnlyLoginUserInfo(LoginUser userInfo, ERPTokenUser currentUser, String dataSourceId, long supplierCode) {
        if (StringUtils.isBlank(userInfo.getUserName())) {
            return RetResult.<LoginUser>errorT().retinfo("用户名不能为空");
        }

        userInfo.setDeptName(deptService.getRedisDeptName(userInfo.getDeptId(), supplierCode));
        LoginUser.update(userInfo, currentUser.getId());


        redisService.hset(keysService.getRedisKey(RedisKeys.KEY_ERP_LOGINUSER, supplierCode), String.valueOf(userInfo.getId()), userInfo);
        systemDao.updateLoginUser2(userInfo, dataSourceId, supplierCode);

        return RetResult.successT();
    }

    @Override
    @SuppressWarnings({"rawtypes", "unchecked"})
    public RetResult<LoginUser> configLoginUserRole(LoginUser userInfo, ERPTokenUser currentUser, String dataSourceId, long supplierCode) {

        RMap params = new RMap();
        params.put("userId", userInfo.getId());

        //配置用户角色信息
        List<UserRole> userRoleList = convertUserRole(userInfo.getId(), userInfo.getRoleIds());
        //覆盖用户角色在redis中的菜单
        roleService.writeRedisUserRole(userInfo.getId(), userRoleList, supplierCode);

        systemDao.configLoginUserRole(params, userRoleList, dataSourceId, supplierCode);

        return RetResult.successT();
    }

    @Override
    public RetResult<LoginUser> voidLoginUser(LoginUser userInfo, ERPTokenUser currentUser, String dataSourceId, long supplierCode) {

        LoginUser redisInfo = getRedisLoginUser(userInfo.getId(), supplierCode);
        if (redisInfo == null) {
            return RetResult.<LoginUser>errorT().retinfo("无效的用户信息");
        }

        redisInfo.setStatus(userInfo.getStatus());

        LoginUser.update(userInfo, currentUser.getId());

        redisService.hset(keysService.getRedisKey(RedisKeys.KEY_ERP_LOGINUSER, supplierCode), String.valueOf(redisInfo.getId()), redisInfo);

        systemDao.voidLoginUser(userInfo, dataSourceId, supplierCode);

        return RetResult.successT();
    }

    @Override
    public RetResult<LoginUser> resetLoginUser(LoginUser userInfo, ERPTokenUser currentUser, String dataSourceId, long supplierCode) {
        userInfo.setPassword(EncryptUtil.md5Digest("123456" + passwordSalt));

        LoginUser.update(userInfo, currentUser.getId());

        systemDao.resetLoginUser(userInfo, dataSourceId, supplierCode);

        return RetResult.successT();
    }

    @Override
    @SuppressWarnings({"rawtypes", "unchecked"})
    public RetResult<LoginUser> changeMyPassword(String oldPassword, String newPassword, ERPTokenUser currentUser, String dataSourceId, long supplierCode) {
        if (currentUser == null) {
            return RetResult.<LoginUser>errorT().retinfo("未登录");
        }

        RMap paramMap = new RMap();

        String md5Password = EncryptUtil.md5Digest(oldPassword + passwordSalt);
        paramMap.put("id", currentUser.getId());
        paramMap.put("loginName", currentUser.getAccount());
        paramMap.put("password", md5Password);
        paramMap.put("companyId", 0L);
        LoginUser destUser = systemDao.login(paramMap, dataSourceId, supplierCode);
        if (destUser == null) {
            return RetResult.<LoginUser>errorT().retinfo("账号或原密码错误");
        }

        paramMap.put("password", EncryptUtil.md5Digest(newPassword + passwordSalt));

        systemDao.changeMyPassword(paramMap, dataSourceId, supplierCode);

        return RetResult.successT();
    }

    //endregion
}
