package com.infoepoch.pms.dispatchassistant.domain.basic.user;

import com.infoepoch.pms.dispatchassistant.common.component.SnowFlake;
import com.infoepoch.pms.dispatchassistant.common.encryption.AESTool;
import com.infoepoch.pms.dispatchassistant.common.exception.NotLoginException;
import com.infoepoch.pms.dispatchassistant.common.exception.ValidationException;
import com.infoepoch.pms.dispatchassistant.common.utils.LambdaTool;
import com.infoepoch.pms.dispatchassistant.common.utils.PasswordTool;
import com.infoepoch.pms.dispatchassistant.common.utils.StringTool;
import com.infoepoch.pms.dispatchassistant.controller.basic.Auth;
import com.infoepoch.pms.dispatchassistant.domain.basic.organization.Organization;
import com.infoepoch.pms.dispatchassistant.domain.basic.organization.OrganizationRoot;
import com.infoepoch.pms.dispatchassistant.domain.basic.organization.OrganizationService;
import com.infoepoch.pms.dispatchassistant.domain.basic.role.IRoleRepository;
import com.infoepoch.pms.dispatchassistant.domain.basic.role.IUserRoleRepository;
import com.infoepoch.pms.dispatchassistant.domain.basic.role.Role;
import com.infoepoch.pms.dispatchassistant.domain.basic.role.RoleService;
import com.infoepoch.pms.dispatchassistant.domain.basic.user.organizationRela.IUserOrganizationRelaRepository;
import com.infoepoch.pms.dispatchassistant.domain.basic.user.organizationRela.UserOrganizationRela;
import com.infoepoch.pms.dispatchassistant.domain.basic.user.organizationRela.UserOrganizationRelaCriteria;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 用户Service
 */
@Service
public class UserService {

    private final static Logger logger = LoggerFactory.getLogger(UserService.class);

    @Autowired
    private Auth auth;
    @Autowired
    IUserRepository userRepository;
    @Autowired
    OrganizationService organizationService;
    @Autowired
    RoleService roleService;

    @Autowired
    private IRoleRepository roleRepository;
    @Autowired
    private IUserRoleRepository userRoleRepository;
    @Autowired
    private IUserOrganizationRelaRepository userOrganizationRelaRepository;

    public List<User> queryUserByOrganizationIdAndRole(String organizationId, String roleName) {
        Role role = roleRepository.selectByRoleName(roleName);
        if (role == null)
            return new ArrayList<>();
        Organization department = OrganizationRoot.getDepartmentById(organizationId);
        if (department != null) {
            List<String> childrenIdList = OrganizationRoot.getChildrenLoopId(department.getId());
            List<User> userList = userRepository.selectByOrganizationIdAndRole(childrenIdList, role.getId());
            setUserListOrganization(userList);
            return userList;
        } else {
            return new ArrayList<>();
        }
    }

    /**
     * 根据id查找用户，找不到返回null
     *
     * @return
     */
    public User getUserById(String id) {
        User user = userRepository.selectById(id);
        if (user == null)
            return null;
        Organization org = OrganizationRoot.getOrganizationById(user.getOrganizationId());
        if (org != null) {
            user.setOrganizationName(org.getName());
        }
        UserOrganizationRelaCriteria userOrganizationRelaCriteria = new UserOrganizationRelaCriteria();
        userOrganizationRelaCriteria.setUserId(user.getId());
        List<UserOrganizationRela> userOrganizationRelaList = userOrganizationRelaRepository.selectByCriteria(userOrganizationRelaCriteria);
        for (UserOrganizationRela userOrganizationRela : userOrganizationRelaList) {
            Organization organization = OrganizationRoot.getOrganizationById(userOrganizationRela.getOrganizationId());
            if (organization != null) {
                userOrganizationRela.setOrganizationName(organization.getName());
            }
        }
        user.setUserOrganizationRelaList(userOrganizationRelaList);
        return user;
    }

    public List<User> getUsersByIds(List<String> ids) {
        List<User> list = userRepository.selectByIds(ids);
        setUserListOrganization(list);
        return list;
    }

    public User selectByUsername(String userName) {
        return userRepository.selectByUsername(userName);
    }

    /**
     * 根据id查找用户，找不到抛出异常
     *
     * @return
     */
    public User getUserByIdReq(String id) throws ValidationException {
        User user = userRepository.selectById(id);
        if (null == user)
            throw new ValidationException("没有找到Id为“" + id + "”的用户。");
        return user;
    }

    /**
     * 根据id集合查找用户，按参数顺序返回
     *
     * @return
     */
    public List<User> getUserByIds(List<String> ids) {
        List<User> users = new ArrayList<>();
        if (ids == null || ids.size() == 0)
            return users;

        UserCriteria criteria = new UserCriteria();
        criteria.setUserIds(ids);
        return userRepository.selectByCriteria(criteria);
    }

    /**
     * @param ids
     * @return
     */
    public Map<String, String> getUserNameMapByIds(List<String> ids) {
        List<User> list = getUserByIds(ids);
        return LambdaTool.changeCollectionToHashMap(list, User::getId, User::getDisplayName);
    }

    //根据角色与组织取用户 组织可为空
    public List<User> getUserByRole(String organizationId, String role) {
        List<User> checkLeaderUserList = roleService.queryUsersByRoleName(role);
        if (StringUtils.isNotBlank(organizationId)) {
            if (CollectionUtils.isNotEmpty(checkLeaderUserList)) {
                Map<String, Organization> organizationMap = OrganizationRoot.getOrganizationMap();
                List<Organization> rootOrganizations = OrganizationRoot.getRootOrganizations();
                Organization department = OrganizationRoot.getDepartmentById(organizationId, organizationMap, rootOrganizations);
                if (department == null)
                    return checkLeaderUserList;
                checkLeaderUserList = checkLeaderUserList.stream().filter(o -> {
                    Organization dept = Optional.ofNullable(OrganizationRoot.getDepartmentById(o.getOrganizationId(), organizationMap, rootOrganizations)).orElse(new Organization());
                    return (StringTool.getString(dept.getId(), "").equals(department.getId())) ||
                            (StringTool.getString(dept.getpId(), "").equals(department.getId()));
                }).collect(Collectors.toList());
                return setUserListOrganization(checkLeaderUserList);
            }
        }
        return setUserListOrganization(checkLeaderUserList);
    }

    /**
     *
     * @param jobNumber
     * @return
     */
    public User getUserByJobNumber(String jobNumber) {
        return userRepository.selectOneByJobNumber(jobNumber);
    }

    /**
     * 根据用户工号查询列表
     *
     * @param jobNumber
     * @return
     */
    public List<User> getUserListByJobNumber(String jobNumber) {
        return userRepository.selectByJobNumber(jobNumber);
    }

    /**
     * 根据工号列表查询用户列表
     *
     * @param jobNumberList
     * @return
     */
    public List<User> getUserListByJobNumbers(List<String> jobNumberList) {
        UserCriteria criteria = new UserCriteria();
        criteria.setJobNumbers(jobNumberList);
        criteria.setDisabled(false);
        return userRepository.selectByCriteria(criteria);
    }

    /**
     * 根据组织ID获取组织下的所有人员
     *
     * @param organizationId 组织ID
     * @param hasChild       是否获取子节点下用户
     * @return
     */
    public List<User> getUserListByOrganizationId(String organizationId, boolean hasChild) {
        List<String> orgIdList = new ArrayList<>();
        orgIdList.add(organizationId);
        if (hasChild) {
            orgIdList.addAll(organizationService.getChildrenOrgIdList(organizationId));
        }
        UserCriteria userCriteria = new UserCriteria();
        userCriteria.setOrganizationIds(orgIdList); // 查询执行组织的
        userCriteria.setDisabled(false); // 未禁用的
        List<User> userList = userRepository.selectByCriteria(userCriteria);
        return userList == null ? new ArrayList<>() : setUserListOrganization(userList);
    }

    public List<User> setUserListOrganization(List<User> userList) {
        List<String> organizationIds = userList.stream().map(User::getOrganizationId).collect(Collectors.toList());
        List<Organization> organizationList = OrganizationRoot.getByIds(organizationIds);

        Map<String, Organization> organizationMap = new HashMap<>();
        if (CollectionUtils.isNotEmpty(organizationList)) {
            organizationList.forEach(organization -> organizationMap.put(organization.getId(), organization));
        }

        return userList.stream().peek(user -> user.setOrganizationName(organizationMap.get(user.getOrganizationId()) != null ? organizationMap.get(user.getOrganizationId()).getName() : "")).collect(Collectors.toList());
    }

    /**
     * 取所有用户，按id倒序
     */
    @Cacheable(cacheNames = "supermarketAllUserList")
    public List<User> getAllUser() {
        //返回的集合为副本，但集合中对象仍是同一个
        List<User> userList = userRepository.selectAll();
        return userList.stream().sorted(Comparator.comparing(User::getDisplayOrderValue)).collect(Collectors.toList());
    }

    @Cacheable(cacheNames = "supermarketUserPick")
    public List<Map<String, Object>> getUserPick() {
        List<Map<String, Object>> map = new ArrayList<>();
        List<User> userList = userRepository.selectAll();
        userList = userList.stream().filter(o -> !o.isDisabled()).collect(Collectors.toList());
        Map<String, List<User>> userMap;
        userMap = userList.stream().collect(Collectors.groupingBy(User::getOrganizationId));
        for (Organization organization : OrganizationRoot.getRootOrganizations()) {
            Map<String, Object> org = getChildrenOrg(organization, userMap);
            if (org != null) {
                map.add(getChildrenOrg(organization, userMap));
            }
        }
        return map;
    }

    /**
     * 基于当前登录用户的组织(本部门人员)，取对应的角色下的人
     *
     * @param role
     * @return
     */
    public List<Map<String, Object>> getUserPickByRole(String role) throws NotLoginException {
        User user = auth.getUserReq();
        Organization organization = Optional.ofNullable(OrganizationRoot.getById(user.getOrganizationId())).orElse(new Organization());
        List<User> checkLeaderUserList = roleService.queryUsersByRoleName(role);
        if (CollectionUtils.isNotEmpty(checkLeaderUserList)) {
            checkLeaderUserList = checkLeaderUserList.stream().filter(o -> {
                // Organization dept = Optional.ofNullable(OrganizationRoot.getRoot().getById(o.getOrganizationId())).orElse(new Organization());
                return StringTool.getString(o.getOrganizationId()).equals(organization.getId());
            }).collect(Collectors.toList());
            return getUserPick(checkLeaderUserList);
        }
        return null;
    }

    /**
     * @param userList
     * @return
     */
    public List<Map<String, Object>> getUserPick(List<User> userList) {
        List<Map<String, Object>> map = new ArrayList<>();
        Map<String, List<User>> userMap = new HashMap<>();
        userMap = userList.stream().collect(Collectors.groupingBy(User::getOrganizationId));
        for (Organization organization : OrganizationRoot.getRootOrganizations()) {
            Map<String, Object> org = getChildrenOrg(organization, userMap);
            if (org != null) {
                map.add(getChildrenOrg(organization, userMap));
            }
        }
        return map;
    }

    //获取下级组织
    private Map<String, Object> getChildrenOrg(Organization organization, Map<String, List<User>> userMap) {
        if (organization.getName().contains("公司领导")) {
            return null;
        }
        Map<String, Object> map = new HashMap<>();
        List<Map<String, Object>> childrenList = new ArrayList<>();
        map.put("value", organization.getId());
        map.put("label", organization.getShortName());
        if (organization.hasChildren()) {
            for (Organization o : organization.getChildren()) {
                Map<String, Object> org = getChildrenOrg(o, userMap);
                if (org != null)
                    childrenList.add(org);
            }
        }
        List<User> rootUserList = userMap.get(organization.getId());
//        if (rootUserList == null) {
//            return null;
//        }
        if (CollectionUtils.isNotEmpty(rootUserList)) {
            for (User user : rootUserList) {
                Map<String, Object> rootChildrenUserPick = new HashMap<>();
                rootChildrenUserPick.put("value", user.getId());
                rootChildrenUserPick.put("label", user.getDisplayName());
                childrenList.add(rootChildrenUserPick);
            }
        }
        if (CollectionUtils.isEmpty(childrenList)) {
            return null;
        }
        map.put("children", childrenList);
        return map;
    }

    /**
     * 删除用户
     */
    public void removeUser(String id) throws ValidationException {
        User user = getUserByIdReq(id);
        userRepository.deleteById(id);
    }

    /**
     * 清空用户
     */
    public void clear() {
        userRepository.truncate();
    }

    /**
     * 根据用户名密码查询用户
     */
    public User getByAuth(String username, String password) throws ValidationException {
        String usr = username == null ? "" : username.trim();
        String pwd = password == null ? "" : password.trim();
        if (StringUtils.isEmpty(usr))
            throw new ValidationException("用户名不能为空。");
        if (StringUtils.isEmpty(pwd))
            throw new ValidationException("密码不能为空。");
        // 给输入的密码加密
        pwd = AESTool.getEncryptString(pwd);
        User user = userRepository.selectByUsername(usr);
        if (user == null)
            throw new ValidationException("您的用户名或密码不正确，请重试！");
        if (!userRepository.selectPassword(user.getId()).equals(pwd))
            throw new ValidationException("您的用户名或密码不正确，请重试！");
        if (user.isDisabled())
            throw new ValidationException("用户被禁用。");
        Organization org = OrganizationRoot.getOrganizationById(user.getOrganizationId());
        user.setOrganizationName(org.getName());
        UserOrganizationRelaCriteria userOrganizationRelaCriteria = new UserOrganizationRelaCriteria();
        userOrganizationRelaCriteria.setUserId(user.getId());
        List<UserOrganizationRela> userOrganizationRelaList = userOrganizationRelaRepository.selectByCriteria(userOrganizationRelaCriteria);
        for (UserOrganizationRela userOrganizationRela : userOrganizationRelaList) {
            Organization organization = OrganizationRoot.getOrganizationById(userOrganizationRela.getOrganizationId());
            if (organization != null) {
                userOrganizationRela.setOrganizationName(organization.getName());
            }
        }
        user.setUserOrganizationRelaList(userOrganizationRelaList);
        return user;
    }

    /**
     * 分页列表
     *
     * @param criteria
     * @return
     */
    public Map<String, Object> pageList(UserCriteria criteria) {
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("list", this.list(criteria));
        resultMap.put("totalCount", userRepository.selectByCriteriaCount(criteria));
        return resultMap;
    }

    public List<User> list(UserCriteria criteria) {
        List<User> userList = userRepository.selectByCriteriaPage(criteria, criteria.getPageIndex(), criteria.getPageSize());
        fillOrganizationName(userList);
        return userList;
    }

    private void fillOrganizationName(List<User> userList) {
        if (CollectionUtils.isEmpty(userList))
            return;
        Map<String, Organization> organizationMap = OrganizationRoot.getOrganizationMap();
        for (User user : userList) {
            Organization organization = organizationMap.get(user.getOrganizationId());
            user.setOrganizationName(organization == null ? null : organization.getName());
        }
    }

    /**
     * @param criteria
     * @return
     */
    public List<User> queryListByCriteria(UserCriteria criteria) {
        List<User> userList = userRepository.selectByCriteria(criteria);
        fillOrganizationName(userList);
        return userList;
    }

    /**
     * @param criteria
     * @param pageIndex
     * @param pageSize
     * @return
     */
    public List<User> queryByCriteriaPage(UserCriteria criteria, int pageIndex, int pageSize) {
        return userRepository.selectByCriteriaPage(criteria, pageIndex, pageSize);
    }

    /**
     * @param criteria
     * @return
     */
    public int queryByCriteriaCount(UserCriteria criteria) {
        return userRepository.selectByCriteriaCount(criteria);
    }

    /**
     * 保存用户
     *
     * @param user
     */
    public void save(User user) {
        if (StringUtils.isBlank(user.getId())) {
            User add = new User(
                    String.valueOf(SnowFlake.instant().nextId()),
                    user.getOrganizationId(),
                    UserType.NORMAL,
                    user.getPosition(),
                    user.getDisplayOrder(),
                    null,
                    user.getUsername(),
                    user.getFullname(),
                    user.getSex(),
                    user.getMobile(),
                    user.getEmail(),
                    false,
                    user.getDescription(),
                    user.getOaData(),
                    user.getHrData(),
                    user.getJobNumber(),
                    user.getOrgConfirmStatus()
            );
            userRepository.insert(add);
            userRepository.updatePassword(add.getId(), "info_epoch");
            // 新增用户时默认绑定普通员工角色
            try {
                Role role = roleRepository.selectByRoleName("普通员工");
                if (role == null) {
                    throw new ValidationException("未查询到角色【普通员工】");
                }
                userRoleRepository.batchInsert(Collections.singletonList(String.valueOf(SnowFlake.instant().nextId())),role.getId(), Collections.singletonList(add.getId()));
            } catch (Exception e) {
                logger.info(e.getMessage());
                e.printStackTrace();
            }
        } else {
            User old = userRepository.selectById(user.getId());
            if (old == null)
                throw new ValidationException("无效的用户ID");
            old.modify(
                    user.getOrganizationId(),
                    user.getType(),
                    user.getPosition(),
                    user.getDisplayOrder(),
                    user.getPermissions(),
                    user.getUsername(),
                    user.getFullname(),
                    user.getSex(),
                    user.getMobile(),
                    user.getEmail(),
                    user.isDisabled(),
                    user.getDescription(),
                    user.getJobNumber(),
                    user.getOrgConfirmStatus()
            );
            userRepository.update(old);
        }
    }

    /**
     * 根据ID删除用户
     *
     * @param id
     */
    public void removeById(String id) {
        userRepository.deleteById(id);
    }

    /**
     * 修改用户密码
     *
     * @param changePassword
     */
    public void changePassword(ChangePassword changePassword) {
        if (StringUtils.isBlank(changePassword.getUserId()))
            throw new ValidationException("用户ID不可为空");
        User user = userRepository.selectById(changePassword.getUserId());
        if (user == null)
            throw new ValidationException("无效的用户ID");
        String password = userRepository.selectPassword(changePassword.getUserId());
        if (StringUtils.isNotBlank(password) && StringUtils.isBlank(changePassword.getPassword()))
            throw new ValidationException("旧密码不可为空");
        String encryptOldPassword = AESTool.getEncryptString(changePassword.getOldPassword());
        if (!password.equals(encryptOldPassword)) {
            throw new ValidationException("旧密码输入错误");
        }
        if (StringUtils.isBlank(changePassword.getPassword()))
            throw new ValidationException("新密码不可为空");
        if (PasswordTool.validationReverse(changePassword.getPassword())) {
            throw new ValidationException("新密码不符合规范：" + PasswordTool.VALIDATION_WARN);
        }
        // 修改用户密码
        userRepository.updatePassword(changePassword.getUserId(), changePassword.getPassword());
    }

    /**
     * 获取工号选择树
     *
     * @return
     */
    @Cacheable(cacheNames = "supermarketJobUserPick")
    public List<Map<String, Object>> getJobPick() {
        List<Map<String, Object>> map = new ArrayList<>();
        List<User> userList = userRepository.selectAll();
        Map<String, List<User>> userMap = new HashMap<>();
        userMap = userList.stream().collect(Collectors.groupingBy(User::getOrganizationId));
        for (Organization organization : OrganizationRoot.getRootOrganizations()) {
            Map<String, Object> org = getJobChildrenOrg(organization, userMap);
            if (org != null) {
                map.add(getJobChildrenOrg(organization, userMap));
            }
        }
        return map;
    }

    /**
     * 获取工号选择树
     *
     * @param userList
     * @return
     */
    public List<Map<String, Object>> getJobPick(List<User> userList) {
        List<Map<String, Object>> map = new ArrayList<>();
        Map<String, List<User>> userMap = new HashMap<>();
        userMap = userList.stream().collect(Collectors.groupingBy(User::getOrganizationId));
        for (Organization organization : OrganizationRoot.getRootOrganizations()) {
            Map<String, Object> org = getJobChildrenOrg(organization, userMap);
            if (org != null) {
                map.add(getJobChildrenOrg(organization, userMap));
            }
        }
        return map;
    }

    private Map<String, Object> getJobChildrenOrg(Organization organization, Map<String, List<User>> jobMap) {
        if (organization.getName().contains("公司领导")) {
            return null;
        }
        Map<String, Object> map = new HashMap<>();
        List<Map<String, Object>> childrenList = new ArrayList<>();
        map.put("value", organization.getId());
        map.put("label", organization.getName());
        if (organization.hasChildren()) {
            for (Organization o : organization.getChildren()) {
                Map<String, Object> org = getJobChildrenOrg(o, jobMap);
                if (org != null)
                    childrenList.add(org);
            }
        }
        List<User> rootUserList = jobMap.get(organization.getId());
//        if (rootUserList == null) {
//            return null;
//        }
        if (CollectionUtils.isNotEmpty(rootUserList)) {
            for (User user : rootUserList) {
                Map<String, Object> rootChildrenUserPick = new HashMap<>();
                rootChildrenUserPick.put("value", user.getId());
                rootChildrenUserPick.put("label", user.getDisplayName() + "(" + user.getJobNumber() + ")");
                childrenList.add(rootChildrenUserPick);
            }
        }
        if (CollectionUtils.isEmpty(childrenList)) {
            return null;
        }
        map.put("children", childrenList);
        return map;
    }

}
