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


import com.infoepoch.pms.dispatchassistant.common.component.SnowFlake;
import com.infoepoch.pms.dispatchassistant.common.exception.ValidationException;
import com.infoepoch.pms.dispatchassistant.domain.basic.menu.IMenuRepository;
import com.infoepoch.pms.dispatchassistant.domain.basic.menu.Menu;
import com.infoepoch.pms.dispatchassistant.domain.basic.organization.Organization;
import com.infoepoch.pms.dispatchassistant.domain.basic.organization.OrganizationCriteria;
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.user.IUserRepository;
import com.infoepoch.pms.dispatchassistant.domain.basic.user.User;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

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

/**
 * @author xuyj
 * @description 角色服务类
 * @date 2019-11-12 11:33
 */
@Service
public class RoleService {

    @Autowired
    IRoleRepository roleRepository;
    @Autowired
    IUserRoleRepository userRoleRepository;
    @Autowired
    IRoleMenuRepository roleMenuRepository;
    @Autowired
    IMenuRepository menuRepository;
    @Autowired
    IUserRepository userRepository;
    @Autowired
    OrganizationService organizationService;

    /**
     * @param roleId
     * @param copyRoleId
     */
    public void copyRelateUser(String roleId, String copyRoleId) {
        Role role = roleRepository.selectById(roleId);
        if (role == null) {
            throw new ValidationException("角色不存在");
        }
        Role copyRole = roleRepository.selectById(copyRoleId);
        if (copyRole == null) {
            throw new ValidationException("复制角色不存在");
        }
        List<String> userIdList = userRoleRepository.selectRelateUserIdList(roleId);
        List<String> copyUserIdList = userRoleRepository.selectRelateUserIdList(copyRoleId);
        copyUserIdList.removeIf(userIdList::contains);
        if (CollectionUtils.isNotEmpty(copyUserIdList)) {
            List<String> ids=new ArrayList<>();
            for (String item:
            copyUserIdList) {
                ids.add(String.valueOf(SnowFlake.instant().nextId()));
            }
            userRoleRepository.batchInsert(ids,roleId, copyUserIdList);
        }
    }

    /**
     * 查询用户角色
     *
     * @param userId 用户id
     * @return
     */
    public List<Role> queryByUserId(String userId) {
        return roleRepository.selectByUserId(userId);
    }

    /**
     * 根据角色名查询关联的用户
     *
     * @param roleName
     * @return
     */
    public List<User> queryUsersByRoleName(String roleName) {
        Role role = roleRepository.selectByRoleName(roleName);
        if (null == role) {
            return Collections.EMPTY_LIST;
        }
        List<User> userList = userRoleRepository.select(role.getId());
        // 过滤掉禁用的用户
        userList = userList.stream().filter(s -> !s.isDisabled()).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(userList)) {
            List<String> organizationIdList = userList.stream().map(User::getOrganizationId).collect(Collectors.toList());
            OrganizationCriteria organizationCriteria = new OrganizationCriteria();
            organizationCriteria.setOrgIdList(organizationIdList);
            List<Organization> organizationList = organizationService.queryByCriteria(organizationCriteria);
            Map<String, Organization> organizationMap = organizationList.stream().collect(Collectors.toMap(Organization::getId, s -> s));
            userList.forEach(user -> {
                Organization organization = organizationMap.get(user.getOrganizationId());
                if (organization != null) {
                    user.setOrganizationName(organization.getName());
                }
            });
        }
        return userList;
    }

    /**
     * 根据角色名查询单个用户
     *
     * @param roleName
     * @return
     */
    public User queryUsers1ByRoleName(String roleName) {
        Role role = roleRepository.selectByRoleName(roleName);
        if (null == role) {
            return null;
        }
        List<User> user = userRoleRepository.select(role.getId());
        // 过滤掉禁用的用户
        user = user.stream().filter(s -> !s.isDisabled()).collect(Collectors.toList());
        if (user == null || user.size() == 0) {
            return null;
        }
        return user.get(0);
    }


    /**
     * 根据部门及角色名查询关联的用户
     *
     * @param roleName
     * @return
     */
    public List<User> queryUsersByRoleName(String roleName, String orgId) {
        List<User> users = queryUsersByRoleName(roleName);
        if (null == users || users.isEmpty()) {
            return null;
        }
        Organization organization = OrganizationRoot.getById(orgId);
        if (organization == null)
            return null;
        List<String> organizationIdList = organization.getAllChildrenId(true);
        users = users.stream()
                .filter(s -> !s.isDisabled()) // 过滤掉禁用的用户
                .filter(s -> organizationIdList.contains(s.getOrganizationId())) // 筛选指定部门的用户
                .collect(Collectors.toList());
        return users;
    }

    /**
     * 判断用户是否包含某个角色
     *
     * @param userId    用户id
     * @param roleNames 角色名集合
     * @return
     */
    public boolean hasRole(String userId, List<String> roleNames) {
        List<Role> roles = queryByUserId(userId);
        if (null == roles || roles.isEmpty()) {
            return false;
        }
        for (String roleName : roleNames) {
            for (Role role : roles) {
                if (roleName.equals(role.getName())) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 判断用户是否包含某个角色
     *
     * @param userId   用户id
     * @param roleName 角色名
     * @return
     */
    public boolean hasRole(String userId, String roleName) {
        List<String> roleNames = new ArrayList<>(1);
        roleNames.add(roleName);
        return hasRole(userId, roleNames);
    }


    /**
     * 分页根据条件查询角色
     *
     * @param criteria
     * @return
     */
    public List<Role> queryByPage(RoleCriteria criteria) {
        return roleRepository.queryByPage(criteria, criteria.getPageIndex(), criteria.getPageSize());
    }

    /**
     * 查询总数量
     *
     * @param criteria
     * @return
     */
    public int queryByPageCount(RoleCriteria criteria) {
        return roleRepository.queryByPageCount(criteria);
    }

    /**
     * 新增角色
     *
     * @param name        角色名称
     * @param description
     * @param disabled
     */
    public void createRole(String name, String description, boolean disabled) {
        Role role = new Role(name, description, disabled);
        roleRepository.insert(role);
    }

    /**
     * 修改角色
     *
     * @param id
     * @param name        角色名称
     * @param description 角色描述
     * @param disabled    是否禁用
     */
    public void modifyRole(String id, String name, String description, boolean disabled) {
        Role role = new Role(id, name, description, disabled);
        roleRepository.update(role);
    }

    /**
     * 删除角色
     *
     * @param roleId
     */
    public void removeRole(String roleId) {
        //step.1 删除角色菜单关联表
        //step.2 删除角色用户关联表
        //step.3 删除角色
        roleMenuRepository.deleteAll(roleId);
        userRoleRepository.deleteAll(roleId);
        roleRepository.delete(roleId);
    }

    /**
     * 角色关联多个用户
     *
     * @param roleId  角色id
     * @param userIds 用户id集合
     */
    public void relateUsers(String roleId, List<String> userIds) {
        //先删除在插入
        userRoleRepository.deleteAll(roleId);
        if (null != userIds && !userIds.isEmpty()) {
            List<String> ids=new ArrayList<>();
            for (String item:
                    userIds) {
                ids.add(String.valueOf(SnowFlake.instant().nextId()));
            }
            userRoleRepository.batchInsert(ids,roleId, userIds);
        }
    }

    /**
     * 角色关联多个用户（分公司）
     *
     * @param orgId
     * @param roleId
     * @param userIds
     */
    public void relateUsers(String orgId, String roleId, List<String> userIds) {
        List<String> children = organizationService.getChildrenOrgIdList(orgId);
        children.add(orgId);
        // 先删除分公司下关联的人员
        userRoleRepository.deleteByRoleIdAndOrgIdList(roleId, children);
        // 插入分公司下关联的人员
        if (CollectionUtils.isNotEmpty(userIds)) {
            List<String> ids=new ArrayList<>();
            for (String item:
                    userIds) {
                ids.add(String.valueOf(SnowFlake.instant().nextId()));
            }
            userRoleRepository.batchInsert(ids, roleId, userIds);
        }
    }

    /**
     * 角色关联多个菜单
     *
     * @param roleId  角色id
     * @param menuIds 菜单id集合
     */
    public void relateMenus(String roleId, List<String> menuIds, List<String> invoiceList) {
        //先删除在插入
        roleMenuRepository.deleteAll(roleId);
        if (null != menuIds && !menuIds.isEmpty()) {
            List<String> ids=new ArrayList<>();
            for (String item:
                    menuIds) {
                ids.add(String.valueOf(SnowFlake.instant().nextId()));
            }

            roleMenuRepository.batchInsert(ids,roleId, menuIds, invoiceList);
        }
    }

    /**
     * 查询关联菜单树，选中
     *
     * @param roleId
     * @param type
     * @return
     */
    public List<Menu> queryRelateMenus(String roleId, int type) {
        //查询所有菜单
        List<Menu> allMenus = menuRepository.selectAll(type);
        //查询当前角色关联的菜单
        List<Menu> relateMenus = roleMenuRepository.select(roleId);
        for (Menu allMenu : allMenus) {
            for (Menu relateMenu : relateMenus) {
                if (allMenu.getId().equals(relateMenu.getId())) {
                    allMenu.setChecked(true);
                    allMenu.setInvoice(relateMenu.getInvoice());
                    break;
                }
            }
        }
        List<Menu> topNode = allMenus.stream().filter(menu -> menu.getParentId() == null).collect(Collectors.toList());
        //从源菜单中删除顶级节点
        allMenus.removeAll(topNode);
        for (Menu menu : topNode) {
            recursiveMenus(menu, allMenus);
        }
        return allMenus;
    }

    /**
     * 递归寻找父节点的所有children
     *
     * @param topNode
     * @param menus
     */
    private void recursiveMenus(Menu topNode, List<Menu> menus) {
        List<Menu> children = new ArrayList<>();
        Iterator<Menu> iterator = menus.iterator();
        while (iterator.hasNext()) {
            Menu menu = iterator.next();
            if (menu.getParentId().equals(topNode.getId())) {
                children.add(menu);
                recursiveMenus(menu, menus);
            }
        }
        topNode.setChildren(children);
    }

    /**
     * 获取角色关联的用户
     *
     * @param roleId 角色id
     * @return
     */
    public List<User> querySelectedUsers(String roleId) {
        return userRoleRepository.select(roleId);
    }

    /**
     * @param selectedUsers
     * @return
     */
    public List<User> distinctUsers(List<User> selectedUsers) {
        List<User> users = userRepository.selectAll();
        users.removeAll(selectedUsers);
        return users;
    }


    /**
     * 未设置该角色的用户
     *
     * @param roleId
     * @param parentOrgId
     * @return
     */
    public List<User> queryNotSelectedUserList(String roleId, String parentOrgId) {
        return userRoleRepository.selectNotSelectedUserByRoleId(roleId, parentOrgId);
    }

    /**
     * 已设置该角色的用户
     *
     * @param roleId
     * @param parentOrgId
     * @return
     */
    public List<User> querySelectedUserList(String roleId, String parentOrgId) {
        return userRoleRepository.selectSelectedUserByRoleId(roleId, parentOrgId);
    }

    /**
     * 根据部门+名称查询未设置该角色的用户
     *
     * @param roleId
     * @param parentOrgId
     * @return
     */
    public List<User> queryNotSelectedUserList(String roleId, String parentOrgId, String fullName) {
        return userRoleRepository.selectNotSelectedUserByRoleId(roleId, parentOrgId, fullName);
    }

}
