package com.cool.store.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.cool.store.constants.CommonConstants;
import com.cool.store.dao.*;
import com.cool.store.dto.buser.UserEventDTO;
import com.cool.store.dto.dept.DepartmentEventDTO;
import com.cool.store.dto.enterprise.*;
import com.cool.store.entity.*;
import com.cool.store.enums.DataSourceEnum;
import com.cool.store.enums.ErrorCodeEnum;
import com.cool.store.enums.FSEventTypeEnum;
import com.cool.store.exception.ServiceException;
import com.cool.store.http.ISVHttpRequest;
import com.cool.store.service.EnterpriseSyncService;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.ListUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

import static com.cool.store.enums.FSEventTypeEnum.*;

/**
 * @author zhangchenbiao
 * @FileName: EnterpriseInitService
 * @Description: 企业初始化
 * @date 2023-05-26 16:28
 */

@Slf4j
@Service
public class EnterpriseSyncServiceImpl implements EnterpriseSyncService {

    @Resource
    private ISVHttpRequest isvHttpRequest;
    @Resource
    private RegionDAO regionDAO;
    @Resource
    private EnterpriseUserDAO enterpriseUserDAO;
    @Resource
    private EnterpriseUserRoleDAO enterpriseUserRoleDAO;
    @Resource
    private SysRoleDAO sysRoleDAO;
    @Resource
    private UserRegionMappingDAO userRegionMappingDAO;

    @Override
    public void syncAll() {
        AuthScopeDTO authScope = isvHttpRequest.getAuthScope();
        List<String> authUserIdList = authScope.getUserIdList();
        //同步部门
        Pair<List<RegionDO>, Multimap<String, String>> listMultimapPair = syncRegion();
        List<RegionDO> regionList = listMultimapPair.getKey();
        Multimap<String, String> leaderDeptMap = listMultimapPair.getValue();
        Multimap<String, String> roleUserMap = ArrayListMultimap.create();
        //同步用户及部门
        syncUserAndUserRegion(regionList, authUserIdList, roleUserMap, leaderDeptMap);
        //处理用户角色 删除多余的角色
        if(!roleUserMap.isEmpty()){
            List<SysRoleDO> insertOrUpdateList = new ArrayList<>();
            List<EnterpriseUserRoleDO> userRoleInsertOrUpdateList = new ArrayList<>();
            List<String> roleIds = new ArrayList<>();
            for (String roleName : roleUserMap.keys()) {
                SysRoleDO sysRole = SysRoleDO.convertSyncDO(roleName);
                roleIds.add(sysRole.getRoleId());
                Collection<String> userIds = roleUserMap.get(roleName);
                insertOrUpdateList.add(sysRole);
                userRoleInsertOrUpdateList.addAll(EnterpriseUserRoleDO.convertSyncDO(sysRole.getRoleId(), new ArrayList<>(userIds)));
                //删除角色下不存在的用户
                enterpriseUserRoleDAO.deleteRoleInUser(sysRole.getRoleId(), DataSourceEnum.SYNC, new ArrayList<>(userIds));
            }
            sysRoleDAO.batchInsertSelective(insertOrUpdateList);
            enterpriseUserRoleDAO.batchInsertOrUpdate(userRoleInsertOrUpdateList);
            //删除不存在的角色？
            sysRoleDAO.deleteRole(DataSourceEnum.SYNC, roleIds);
        }else {
            //如果为空 是不是得删除角色 及用户角色信息？
        }
    }

    /**
     * 同步组织架构
     * @return
     */
    private Pair<List<RegionDO>, Multimap<String, String>> syncRegion(){
        //同步部门
        List<SysDepartmentDTO> departments = isvHttpRequest.getSubDepartments(CommonConstants.ROOT_DEPT_ID_STR, true);
        //获取企业信息
        AuthInfoDTO authInfo = isvHttpRequest.getAuthInfo();
        Multimap<String, String> leaderDeptMap = ArrayListMultimap.create();
        //组织架构中增加根节点，处理部门上下级关系
        List<RegionDO> regionList = SysDepartmentDTO.convertRegionDO(departments, leaderDeptMap);
        //添加根节点
        regionList.add(getRootRegion(authInfo));
        List<String> regionIds = regionList.stream().map(RegionDO::getRegionId).distinct().collect(Collectors.toList());
        //批量插入
        regionDAO.batchInsertOrUpdate(regionList);
        //删除不存在的区域
        regionDAO.deleteNotExistRegion(regionIds);
        //删除区域管理的人员
        userRegionMappingDAO.deleteRegionUserByExcludeRegionIds(regionIds);
        return Pair.of(regionList, leaderDeptMap);
    }

    /**
     * 处理用户及部门之间的关系
     * @param regionList
     * @param roleUserMap
     * @param leaderDeptMap
     */
    private void syncUserAndUserRegion(List<RegionDO> regionList, List<String> authUserIdList, Multimap<String, String> roleUserMap, Multimap<String, String> leaderDeptMap){
        Map<String, String> regionPathMap = regionList.stream().collect(Collectors.toMap(RegionDO::getRegionId, RegionDO::getRegionPath));
        List<EnterpriseUserDO> userList = new ArrayList<>();
        List<UserRegionMappingDO> userRegionList = new ArrayList<>();
        List<String> userIds = new ArrayList<>();
        //按部门获取用户
        for (RegionDO region : regionList) {
            List<EnterpriseUserDTO> departmentUsers = isvHttpRequest.getDepartmentUsers(region.getRegionId());
            List<String> deptUserIds = ListUtils.emptyIfNull(departmentUsers).stream().map(EnterpriseUserDTO::getUserId).collect(Collectors.toList());
            userRegionMappingDAO.deleteUserRegion(region.getRegionId(), DataSourceEnum.SYNC, deptUserIds);
            if(CollectionUtils.isEmpty(departmentUsers)){
                continue;
            }
            userIds.addAll(deptUserIds);
            userRegionList.addAll(UserRegionMappingDO.convertSyncDO(region.getRegionId(), departmentUsers));
            //系统内的角色 获取飞书的职务  一个人只能一个职务
            List<EnterpriseUserDO> deptUserList = EnterpriseUserDTO.transUserDtoToDo(departmentUsers, regionPathMap, leaderDeptMap, roleUserMap);
            userList.addAll(deptUserList);
            if(userList.size() > CommonConstants.DEAL_RECORD_MAX_SIZE){
                enterpriseUserDAO.batchInsertOrUpdate(userList);
                userList.clear();
            }
            if(userRegionList.size() > CommonConstants.DEAL_RECORD_MAX_SIZE){
                userRegionMappingDAO.batchInsertOrUpdateUserRegion(userRegionList);
                userRegionList.clear();
            }
        }
        if(CollectionUtils.isNotEmpty(authUserIdList)){
            userIds.addAll(authUserIdList);
            List<EnterpriseUserDTO> userDetailList = isvHttpRequest.getUserDetailByUserIds(authUserIdList);
            List<EnterpriseUserDO> enterpriseUserList = EnterpriseUserDTO.transUserDtoToDo(userDetailList, regionPathMap, leaderDeptMap, roleUserMap);
            List<UserRegionMappingDO> userRegionMapping = UserRegionMappingDO.convertSyncDO(enterpriseUserList);
            userRegionList.addAll(userRegionMapping);
            userList.addAll(enterpriseUserList);
        }
        enterpriseUserDAO.batchInsertOrUpdate(userList);
        userRegionMappingDAO.batchInsertOrUpdateUserRegion(userRegionList);
        //删除不存在的用户
        enterpriseUserDAO.deleteUser(userIds);
        userRegionMappingDAO.deleteRegionUserByExcludeUserIds(userIds);
    }

    /**
     * 获取跟部门
     * @param authInfo
     * @return
     */
    private RegionDO getRootRegion(AuthInfoDTO authInfo){
        RegionDO rootRegion = new RegionDO();
        rootRegion.setName(authInfo.getAuthCorpInfo().getCorpName());
        rootRegion.setRegionId(CommonConstants.ROOT_DEPT_ID_STR);
        rootRegion.setParentId(CommonConstants.ZERO_STR);
        rootRegion.setThirdDeptId(CommonConstants.ROOT_DEPT_ID_STR);
        rootRegion.setOrderNum(CommonConstants.ZERO);
        rootRegion.setRegionPath(CommonConstants.PATH_SPILT + rootRegion.getRegionId() + CommonConstants.PATH_SPILT);
        rootRegion.setDeleted(Boolean.FALSE);
        return rootRegion;
    }

    @Override
    public void userUpdateEvent(UserEventDTO param) {
        FSEventTypeEnum eventType = parseValue(param.getEventType());
        switch (eventType){
            case USER_CREATED:
            case USER_UPDATED:
                EnterpriseUserDTO userDetail = isvHttpRequest.getUserDetailByUserId(param.getOpenId());
                List<String> departmentLists = userDetail.getDepartmentLists();
                Multimap<String, String> leaderDeptMap = ArrayListMultimap.create();
                Map<String, String> regionPathMap = new HashMap<>();
                if(CollectionUtils.isNotEmpty(departmentLists)){
                    List<RegionDO> regionList = regionDAO.getRegionByRegionIds(departmentLists);
                    List<String> regionIds = ListUtils.emptyIfNull(regionList).stream().map(RegionDO::getRegionId).collect(Collectors.toList());
                    //判断两个集合是否都是包含关系，不包含的情况下 说明组织架构数据不全 重新同步
                    if(!(regionIds.containsAll(departmentLists) && departmentLists.containsAll(regionIds))){
                        Pair<List<RegionDO>, Multimap<String, String>> regionPair = syncRegion();
                        regionList = regionPair.getKey();
                        leaderDeptMap = regionPair.getValue();
                    }
                    regionPathMap = regionList.stream().collect(Collectors.toMap(k->k.getRegionId(), v->v.getRegionPath()));
                }
                String jobTitle = userDetail.getJobTitle();
                if(StringUtils.isNotBlank(jobTitle)){
                    SysRoleDO role = sysRoleDAO.getRoleByName(jobTitle, DataSourceEnum.SYNC);
                    if(Objects.isNull(role)){
                        //新增角色
                        role = SysRoleDO.convertSyncDO(jobTitle);
                        sysRoleDAO.batchInsertSelective(new ArrayList<>(Arrays.asList(role)));
                    }
                    List<EnterpriseUserRoleDO> enterpriseUserRole = EnterpriseUserRoleDO.convertSyncDO(role.getRoleId(), new ArrayList<>(Arrays.asList(userDetail.getUserId())));
                    enterpriseUserRoleDAO.batchInsertOrUpdate(enterpriseUserRole);
                    enterpriseUserRoleDAO.deleteUserInRole(userDetail.getUserId(), DataSourceEnum.SYNC, role.getRoleId());
                }else{
                    enterpriseUserRoleDAO.deleteUserRole(userDetail.getUserId());
                }
                EnterpriseUserDO enterpriseUser = EnterpriseUserDTO.transUserDtoToDo(userDetail, regionPathMap, leaderDeptMap, eventType);
                enterpriseUserDAO.batchInsertOrUpdate(new ArrayList<>(Arrays.asList(enterpriseUser)));
                userRegionMappingDAO.batchInsertOrUpdateUserRegion(UserRegionMappingDO.convertSyncDO(Arrays.asList(enterpriseUser)));
                userRegionMappingDAO.deleteUserRegionByUserId(userDetail.getUserId(), DataSourceEnum.SYNC, departmentLists);
                break;
            case USER_DELETED:
                //人员职位删除状态，角色职位删除状态，人员从部门去除
                userRegionMappingDAO.deleteUserRegionByUserId(param.getUserId());
                enterpriseUserRoleDAO.deleteUserRole(param.getUserId());
                enterpriseUserDAO.deleteUserByUserId(param.getUserId());
                break;
            default:
                return;
        }
    }

    @Override
    public void deptUpdateEvent(DepartmentEventDTO param) {
        SysDepartmentDTO departmentDetail = isvHttpRequest.getDepartmentDetail(param.getDepartmentId());
        if(Objects.isNull(departmentDetail)){
            return;
        }
        log.info("部门变更：{}", JSONObject.toJSONString(param));
        switch (parseValue(param.getEventType())){
            case DEPARTMENT_CREATED:
                RegionDO parentRegionInfo = regionDAO.getRegionInfoByRegionId(departmentDetail.getParentId());
                if(Objects.isNull(parentRegionInfo)){
                    throw new ServiceException(ErrorCodeEnum.PARENT_NODE_NOT_EXIST);
                }
                Multimap<String, String> leaderDeptMap = ArrayListMultimap.create();
                RegionDO region = SysDepartmentDTO.convertRegionDO(departmentDetail, leaderDeptMap, parentRegionInfo);
                regionDAO.batchInsertOrUpdate(Arrays.asList(region));
                dealUserLeaderDept(leaderDeptMap);
                break;
            case DEPARTMENT_UPDATED:
                if(param.getIsChangeParent()){
                    syncAll();
                    return;
                }
                Multimap<String, String> updateLeaderDeptMap = ArrayListMultimap.create();
                RegionDO updateRegion = SysDepartmentDTO.convertRegionDO(departmentDetail, updateLeaderDeptMap);
                regionDAO.batchInsertOrUpdate(Arrays.asList(updateRegion));
                dealUserLeaderDept(updateLeaderDeptMap);
                break;
            case DEPARTMENT_DELETED:
                boolean leafNode = regionDAO.isLeafNode(departmentDetail.getId());
                boolean isExistUser = enterpriseUserDAO.isExistDeptUser(departmentDetail.getId());
                if(leafNode && !isExistUser){
                    //叶子节点的时候会删除部门
                    regionDAO.deleteRegionByRegionId(departmentDetail.getId());
                    //清除负责人信息
                    List<EnterpriseUserDO> leaderUserList = enterpriseUserDAO.getUserListByDeptLeader(departmentDetail.getId());
                    for (EnterpriseUserDO enterpriseUser : leaderUserList) {
                        List<String> existDeptIds = JSONObject.parseArray(enterpriseUser.getLeaderDeptIds()).stream().map(String::valueOf).collect(Collectors.toList());
                        if(CollectionUtils.isNotEmpty(existDeptIds)){
                            existDeptIds.remove(departmentDetail.getId());
                        }
                        enterpriseUser.setLeaderDeptIds(JSONObject.toJSONString(existDeptIds));
                    }
                    enterpriseUserDAO.batchInsertOrUpdate(leaderUserList);
                }else{
                    syncAll();
                }
                break;
            default:
                return;
        }
    }

    /**
     * 处理用户负责部门信息
     * @param leaderDeptMap
     */
    public void dealUserLeaderDept(Multimap<String, String> leaderDeptMap){
        if(leaderDeptMap.isEmpty()){
            return;
        }
        List<String> userIds = leaderDeptMap.keys().stream().collect(Collectors.toList());
        List<EnterpriseUserDO> userList = enterpriseUserDAO.getUserInfoByUserIds(userIds);
        for (EnterpriseUserDO enterpriseUser : userList) {
            List<String> deptIds = leaderDeptMap.get(enterpriseUser.getUserId()).stream().collect(Collectors.toList());
            String leaderDeptIds = enterpriseUser.getLeaderDeptIds();
            if(StringUtils.isNotBlank(leaderDeptIds)){
                List<String> existDeptIds = JSONObject.parseArray(leaderDeptIds).stream().map(String::valueOf).collect(Collectors.toList());
                //取并集
                existDeptIds.addAll(deptIds);
                List<String> allDeptIds = existDeptIds.stream().distinct().collect(Collectors.toList());
                enterpriseUser.setLeaderDeptIds(JSONObject.toJSONString(allDeptIds));
            }else{
                enterpriseUser.setLeaderDeptIds(JSONObject.toJSONString(deptIds));
            }
            enterpriseUser.setIsLeader(Boolean.TRUE);
        }
        enterpriseUserDAO.batchInsertOrUpdate(userList);
    }

}
