package com.keyware.shandan.system.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.keyware.shandan.bianmu.service.DirectoryMembersService;
import com.keyware.shandan.bianmu.service.DirectoryService;
import com.keyware.shandan.common.entity.BaseEntity;
import com.keyware.shandan.common.entity.Result;
import com.keyware.shandan.common.service.BaseServiceImpl;
import com.keyware.shandan.common.util.IDGenerator;
import com.keyware.shandan.common.util.StringUtils;
import com.keyware.shandan.frame.annotation.DataPermissions;
import com.keyware.shandan.system.entity.SysOrg;
import com.keyware.shandan.system.entity.SysUser;
import com.keyware.shandan.system.mapper.SysOrgMapper;
import com.keyware.shandan.system.service.SysOrgService;
import com.keyware.shandan.system.service.SysUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

/**
 * <p>
 * 部门表 服务实现类
 * </p>
 *
 * @author GuoXin
 * @since 2021-05-11
 */
@Service
public class SysOrgServiceImpl extends BaseServiceImpl<SysOrgMapper, SysOrg, String> implements SysOrgService {

    @Autowired
    private SysOrgMapper sysOrgMapper;

    @Autowired
    private SysUserService sysUserService;

    @Autowired
    private DirectoryService directoryService;

    @Autowired
    private DirectoryMembersService directoryMembersService;

    @Override
    @DataPermissions(orgColumn = "ID")
    public Page<SysOrg> page(Page<SysOrg> page, QueryWrapper<SysOrg> wrapper) {
        String parentId = wrapper.getEntity().getOrgParentId();
        wrapper.getEntity().setOrgParentId(null);

        if (StringUtils.isNotBlank(parentId)) {
            wrapper.eq("ORG_PARENT_ID", parentId).or().eq("ID", parentId);
        }
        wrapper.orderByAsc("CREATE_TIME");
        Page<SysOrg> orgPage = super.page(page, wrapper);

        orgPage.getRecords().sort((o1, o2) -> o1.getId().equals(parentId) || "ROOT".equals(o1.getId()) ? -1 : 1);
        return orgPage;
    }

    @Override
    public void setOrgLeader(String orgId, SysUser leader) {
        SysOrg org = getById(orgId);
        if (org != null) {
            if (StringUtils.hasText(org.getLeaderUserId()) && !org.getLeaderUserId().equals(leader.getUserId())) {
                //sysUserService.removeOrgLeader(org.getLeaderUserId());
                throw new RuntimeException("该部门已设置主管，若要更改，请先取消主管设置");
            }
            org.setLeaderUserId(leader.getUserId());
            org.setLeaderName(leader.getUserName());
            updateById(org);
        }
    }

    @Override
    public void removeOrgLeader(String orgId) {
        SysOrg org = getById(orgId);
        if (org != null && StringUtils.hasText(org.getLeaderUserId())) {
            SysUser user = sysUserService.getById(org.getLeaderUserId());
            user.setOrgLeader(false);
            sysUserService.updateById(user);

            org.setLeaderName("");
            org.setLeaderUserId("");
            updateById(org);
        }
    }

    /**
     * 获取部门树
     *
     * @param parentId
     * @return
     */
    @Override
    public Result<List<SysOrg>> getOrgTree(String parentId) {

        SysOrg org = sysOrgMapper.getOrgTree(parentId);
        return Result.of(Collections.singletonList(org));
    }

    @Override
    @DataPermissions(orgColumn = "ID")
    public List<SysOrg> list(QueryWrapper<SysOrg> wrapper) {
        return super.list(wrapper);
    }

    @Override
    @Cacheable("SYS_ORG")
    public SysOrg getById(Serializable id) {
        return super.getById(id);
    }

    @Override
    @Cacheable("SYS_ORG")
    public Result<SysOrg> get(String id) {
        return super.get(id);
    }

    /**
     * 获取部门的所有子部门,不包含当前部门
     *
     * @param orgId
     * @return
     */
    @Override
    public List<SysOrg> getOrgAllChildren(String orgId) {
        QueryWrapper<SysOrg> query = new QueryWrapper<>();
        query.ne("ID", orgId).like("ORG_PATH", orgId);
        return list(query);
    }

    /**
     * 查询部门管理员
     *
     * @param orgId
     * @return
     */
    @Override
    public List<SysUser> getOrgAdmins(String orgId) {
        List<SysUser> leaders = sysOrgMapper.selectOrgAdmins(orgId);
        if (leaders.size() == 0) { // 如果当前结构没有管理员，则查找上级机构管理员
            SysOrg org = getById(orgId);
            if (org != null) {
                leaders = getOrgAdmins(org.getOrgParentId());
            }
        }
        return leaders;
    }

    @Override
    public List<SysOrg> tree(String parentId) {
        QueryWrapper<SysOrg> wrapper = new QueryWrapper<>();
        if (StringUtils.isNotBlank(parentId)) {
            SysOrg parent = getById(parentId);
            wrapper.like("ORG_PATH", parent.getOrgPath() + "|%");
        }
        List<SysOrg> list = list(wrapper);
        return generateTree(list);
    }

    @Override
    @DataPermissions(orgColumn = "ID")
    public List<SysOrg> tree(QueryWrapper<SysOrg> wrapper) {
        return generateTree(list(wrapper));
    }

    /**
     * 重写部门的保存方法
     *
     * @param entity 部门
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<SysOrg> updateOrSave(SysOrg entity) throws Exception {
        SysOrg parentOrg = getById(entity.getOrgParentId());
        if (parentOrg == null) {
            return Result.of(null, false, "未查询到上级部门");
        }
        // 如果ID为空则表示新增需要验证orgNumber
        if (StringUtils.isBlank(entity.getId())) {
            QueryWrapper<SysOrg> query = new QueryWrapper<>();
            query.eq("ORG_NUMBER", entity.getOrgNumber()).or().eq("ORG_NAME", entity.getOrgName());
            List<SysOrg> list = list(query);
            if (list != null && list.size() > 0) {
                return Result.of(null, false, "该部门已存在，请检查部门编号和部门名称");
            }
            String uid = IDGenerator.getId();
            entity.setId(uid);
            entity.setOrgNumber(uid);
        }
        // 设置父部门名称
        entity.setOrgParentName(parentOrg.getOrgName());
        // 设置部门路径
        entity.setOrgPath(parentOrg.getOrgPath().concat("|").concat(entity.getOrgNumber()));
        // 设置部门负责人
        if (StringUtils.isNotBlank(entity.getLeaderUserId())) {
            SysUser leader = sysUserService.getById(entity.getLeaderUserId());
            if (leader == null) {
                return Result.of(null, false, "部门负责人不存在");
            }
            entity.setLeaderName(leader.getUserName());
        }

        if (entity.isAutoCreateDir()) {
            // 自动创建目录
            directoryService.autoCreateDirByOrg(entity);
        }
        return super.updateOrSave(entity);
    }

    /**
     * 递归删除子部门
     *
     * @param id
     * @return
     */
    @Override
    public Result<Boolean> deleteById(String id) {
        SysOrg org = getById(id);
        SysOrg parentOrg = getById(org.getOrgParentId());
        List<SysOrg> childrenList = listAllChildByParentId(id);
        childrenList.add(org);
        List<String> idList = childrenList.stream().map(SysOrg::getId).collect(Collectors.toList());

        // 将部门以及所有下级部门的用户迁移到父级部门
        List<SysUser> users = findAllUserByOrgs(idList);
        if (users.size() > 0) {
            moveUsersToNewOrg(users, parentOrg);
        }

        // 移除目录成员
        directoryMembersService.removeByMemberIds(idList);

        // 将目录数据迁移至父级部门
        directoryService.moveDataToNewOrg(childrenList, parentOrg);

        sysOrgMapper.deleteBatchIds(idList);
        return Result.of(true, true);
    }

    @Override
    public void moveUsersToNewOrg(Collection<SysUser> users, SysOrg newOrg) {
        List<String> userIds = users.stream().map(SysUser::getUserId).collect(Collectors.toList());
        UpdateWrapper<SysUser> uw = new UpdateWrapper<>();
        uw.set("ORG_ID", newOrg.getId()).in("USER_ID", userIds);
        sysUserService.update(uw);
    }

    private List<SysUser> findAllUserByOrgs(List<String> idList) {
        QueryWrapper<SysUser> wrapper = new QueryWrapper<>();
        wrapper.in("ORG_ID", idList);
        return sysUserService.list(wrapper);
    }

    /**
     * 根据父菜单Id递归查询子菜单列表
     *
     * @param parentId
     * @return
     */
    public List<SysOrg> listAllChildByParentId(String parentId) {
        List<SysOrg> allChild = new ArrayList<>();

        SysOrg childCondition = new SysOrg();
        childCondition.setOrgParentId(parentId);
        List<SysOrg> child = super.list(new QueryWrapper<>(childCondition));
        if (child != null && child.size() != 0) {
            allChild.addAll(child);
            child.forEach(menu -> {
                allChild.addAll(listAllChildByParentId(menu.getId()));
            });
        }

        return allChild;
    }

    /**
     * 构建部门树
     *
     * @param list
     * @return
     */
    private List<SysOrg> generateTree(List<SysOrg> list) {
        Set<SysOrg> allOrgSet = new HashSet<>(list);

        list.stream()
                // 找到当前部门列表的根部门
                .filter(org -> list.stream().noneMatch(o -> o.getId().equals(org.getOrgParentId())))
                // 根据当前根部门查找所有父部门
                .forEach(org -> allOrgSet.addAll(listByIds(Arrays.asList(org.getOrgPath().split("\\|")))));

        return allOrgSet.stream()
                // 找到根部门
                .filter(org -> allOrgSet.stream().noneMatch(o -> o.getId().equals(org.getOrgParentId())))
                // 递归子部门
                .peek(org -> findChildren(org, new ArrayList<>(allOrgSet))).sorted((o1, o2) -> o2.getCreateTime().compareTo(o1.getCreateTime()))
                // 转换List
                .collect(Collectors.toList());
    }

    /**
     * 递归子部门
     *
     * @param org
     * @param list
     */
    private void findChildren(SysOrg org, List<SysOrg> list) {
        org.setChildren(list.stream().filter(o -> org.getId().equals(o.getOrgParentId())).sorted(Comparator.comparing(BaseEntity::getCreateTime)).collect(Collectors.toList()));
        if (!org.getChildren().isEmpty()) {
            org.getChildren().stream().peek(o -> findChildren(o, list)).collect(Collectors.toList());
        }
    }
}
