package ink.wgink.service.department.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import ink.wgink.common.base.DefaultBaseService;
import ink.wgink.exceptions.SearchException;
import ink.wgink.interfaces.consts.ISystemConstant;
import ink.wgink.interfaces.department.IDepartmentUserDeleteAfterHandler;
import ink.wgink.interfaces.department.IDepartmentUserSaveAfterHandler;
import ink.wgink.interfaces.user.IUserBaseService;
import ink.wgink.interfaces.user.mongo.IMongoLoginUserService;
import ink.wgink.pojo.ListPage;
import ink.wgink.pojo.dtos.department.DepartmentContainUserDTO;
import ink.wgink.pojo.dtos.department.DepartmentDTO;
import ink.wgink.pojo.dtos.department.DepartmentSimpleDTO;
import ink.wgink.pojo.dtos.department.DepartmentUserDTO;
import ink.wgink.pojo.dtos.user.UserDTO;
import ink.wgink.pojo.pos.DepartmentPO;
import ink.wgink.pojo.result.SuccessResultList;
import ink.wgink.service.department.dao.IDepartmentUserDao;
import ink.wgink.service.department.pojo.vos.DepartmentUserSortVO;
import ink.wgink.service.department.service.IDepartmentAdjustmentService;
import ink.wgink.service.department.service.IDepartmentService;
import ink.wgink.service.department.service.IDepartmentUserService;
import ink.wgink.service.user.pojo.pos.UserPO;
import ink.wgink.util.thread.CachedThreadPoolUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * When you feel like quitting. Think about why you started
 * 当你想要放弃的时候，想想当初你为何开始
 *
 * @ClassName: DepartmentUserServiceImpl
 * @Description: 组织部门用户
 * @Author: wanggeng
 * @Date: 2021/1/28 4:21 下午
 * @Version: 1.0
 */
@Service
public class DepartmentUserServiceImpl extends DefaultBaseService implements IDepartmentUserService {

    @Autowired
    private IDepartmentUserDao departmentUserDao;
    @Autowired
    private IDepartmentService departmentService;
    @Autowired
    private IDepartmentAdjustmentService departmentAdjustmentService;
    @Autowired
    private IUserBaseService userBaseService;
    @Autowired(required = false)
    private IDepartmentUserSaveAfterHandler departmentUserSaveAfterHandler;
    @Autowired(required = false)
    private IDepartmentUserDeleteAfterHandler departmentUserDeleteAfterHandler;
    @Autowired(required = false)
    private IMongoLoginUserService mongoLoginUserService;

    @Override
    public void save(String departmentId, String departmentName, List<String> departmentUserIds) {
        List<String> existUserIds = listUserId(departmentId, departmentUserIds);
        Map<String, Object> params = getHashMap(4);
        for (int i = 0; i < departmentUserIds.size(); i++) {
            String saveUserId = departmentUserIds.get(i);
            boolean isExist = false;
            for (String existUserId : existUserIds) {
                if (StringUtils.equals(saveUserId, existUserId)) {
                    isExist = true;
                    existUserIds.remove(existUserId);
                    break;
                }
            }
            if (!isExist) {
                params.put("userId", saveUserId);
                params.put("departmentId", departmentId);
                departmentUserDao.save(params);
            } else {
                departmentUserIds.remove(i);
                i--;
            }
        }
        updateMongoLoginUser(departmentUserIds);
        departmentAdjustmentService.save(existUserIds, departmentId, departmentName, USER_DEPARTMENT_TYPE_JOIN);
        if (departmentUserSaveAfterHandler != null) {
            departmentUserSaveAfterHandler.handle(departmentId, departmentUserIds);
        }
    }

    @Override
    public void save(String departmentId, List<String> userIds) {
        DepartmentPO departmentPO = departmentService.getPO(departmentId);
        if (departmentPO == null) {
            throw new SearchException("部门不存在");
        }
        save(departmentId, departmentPO.getDepartmentName(), userIds);
    }

    @Override
    public void delete(String departmentId, String departmentName, List<String> userIds) {
        String adjustmentDepartmentName = departmentName;
        if (StringUtils.isBlank(departmentName)) {
            DepartmentPO departmentPO = departmentService.getPO(departmentId);
            if (departmentPO == null) {
                throw new SearchException("部门不存在");
            }
            adjustmentDepartmentName = departmentPO.getDepartmentName();
        }
        if (userIds == null || userIds.isEmpty()) {
            return;
        }
        Map<String, Object> params = getHashMap(1);
        params.put("departmentId", departmentId);
        params.put("userIds", userIds);
        departmentUserDao.delete(params);
        updateMongoLoginUser(userIds);
        departmentAdjustmentService.save(userIds, departmentId, adjustmentDepartmentName, USER_DEPARTMENT_TYPE_LEAVE);
        if (departmentUserDeleteAfterHandler != null) {
            departmentUserDeleteAfterHandler.handle(departmentId, userIds);
        }
    }

    @Override
    public void delete(String departmentId) {
        Map<String, Object> params = getHashMap(2);
        params.put("departmentId", departmentId);
        List<String> userIds = departmentUserDao.listUserId(params);
        delete(departmentId, null, userIds);
    }

    @Override
    public void update(String departmentId, List<String> saveUserIds, List<String> deleteUserIds) {
        DepartmentPO departmentPO = departmentService.getPO(departmentId);
        if (departmentPO == null) {
            throw new SearchException("部门不存在");
        }
        if (deleteUserIds != null && !deleteUserIds.isEmpty()) {
            delete(departmentId, departmentPO.getDepartmentName(), deleteUserIds);
        }
        if (saveUserIds != null && !saveUserIds.isEmpty()) {
            Map<String, Object> params = getHashMap(4);
            params.put("departmentId", departmentId);
            for (String userId : saveUserIds) {
                params.put("userId", userId);
                departmentUserDao.save(params);
            }
            updateMongoLoginUser(saveUserIds);
        }
        departmentAdjustmentService.save(saveUserIds, departmentId, departmentPO.getDepartmentName(), USER_DEPARTMENT_TYPE_JOIN);
        if (departmentUserSaveAfterHandler != null) {
            departmentUserSaveAfterHandler.handle(departmentId, saveUserIds);
        }
    }

    @Override
    public void updateSort(String departmentId, DepartmentUserSortVO departmentUserSortVO) {
        Map<String, Object> params = getHashMap(6);
        params.put("departmentId", departmentId);
        params.put("userId", departmentUserSortVO.getUserId());
        params.put("userSort", departmentUserSortVO.getUserSort());
        departmentUserDao.updateSort(params);
    }

    @Override
    public List<DepartmentPO> listDepartmentPOByUserId(String userId) {
        Map<String, Object> params = getHashMap(2);
        params.put("userId", userId);
        List<String> departmentIds = departmentUserDao.listDepartmentId(params);
        if (departmentIds.isEmpty()) {
            return new ArrayList<>();
        }
        return departmentService.listPO(departmentIds);
    }

    @Override
    public List<DepartmentSimpleDTO> listSimple(List<DepartmentPO> departmentPOs) {
        if (departmentPOs == null || departmentPOs.isEmpty()) {
            return new ArrayList<>();
        }
        List<DepartmentSimpleDTO> departmentSimpleDTOs = new ArrayList<>();
        departmentPOs.forEach(departmentPO -> {
            DepartmentSimpleDTO departmentSimpleDTO = new DepartmentSimpleDTO();
            departmentSimpleDTO.setDepartmentId(departmentPO.getDepartmentId());
            departmentSimpleDTO.setDepartmentParentId(departmentPO.getDepartmentParentId());
            departmentSimpleDTO.setDepartmentName(departmentPO.getDepartmentName());
            departmentSimpleDTO.setDepartmentCode(departmentPO.getDepartmentCode());
            departmentSimpleDTOs.add(departmentSimpleDTO);
        });
        return departmentSimpleDTOs;
    }

    @Override
    public List<DepartmentUserDTO> listWithUser(Map<String, Object> params) {
        List<DepartmentUserDTO> departmentUserDTOs = list(params);
        setUser(departmentUserDTOs);
        return departmentUserDTOs;
    }

    @Override
    public List<DepartmentUserDTO> list(Map<String, Object> params) {
        return departmentUserDao.list(params);
    }

    @Override
    public List<DepartmentUserDTO> list(String departmentId) {
        Map<String, Object> params = getHashMap(2);
        params.put("departmentId", departmentId);
        return list(params);
    }

    @Override
    public List<DepartmentUserDTO> listByDepartmentIdAndUserIds(String departmentId, List<String> userIds) {
        Map<String, Object> params = getHashMap(2);
        params.put("departmentId", departmentId);
        params.put("userIds", userIds);
        return list(params);
    }

    @Override
    public List<DepartmentUserDTO> list(List<String> departmentIds) {
        Map<String, Object> params = getHashMap(2);
        params.put("departmentIds", departmentIds);
        return list(params);
    }

    @Override
    public List<DepartmentUserDTO> listByUserIds(List<String> userIds) {
        if (userIds.isEmpty()) {
            return new ArrayList<>();
        }
        Map<String, Object> params = getHashMap(2);
        params.put("userIds", userIds);
        return list(params);
    }

    @Override
    public List<String> listUserId(String departmentId) {
        Map<String, Object> params = getHashMap(2);
        params.put("departmentId", departmentId);
        return departmentUserDao.listUserId(params);
    }

    @Override
    public List<String> listUserId(List<String> departmentIds) {
        Map<String, Object> params = getHashMap(2);
        params.put("departmentIds", departmentIds);
        return departmentUserDao.listUserId(params);
    }

    @Override
    public List<String> listUserId(String departmentId, List<String> userIds) {
        Map<String, Object> params = getHashMap(4);
        params.put("departmentId", departmentId);
        params.put("userIds", userIds);
        return departmentUserDao.listUserId(params);
    }

    @Override
    public List<String> listUserId(List<String> departmentIds, List<String> userIds) {
        Map<String, Object> params = getHashMap(4);
        params.put("departmentIds", departmentIds);
        params.put("userIds", userIds);
        return departmentUserDao.listUserId(params);
    }

    @Override
    public SuccessResultList<List<DepartmentUserDTO>> listPage(String departmentId, ListPage page) {
        if (StringUtils.equals(departmentId, ISystemConstant.TREE_BASE_ROOT_ID_VALUE)) {
            return listPageUserByExcludeDepartment(page);
        }
        return listPageUser(departmentId, page);
    }

    @Override
    public List<DepartmentUserDTO> list(String departmentId, Map<String, Object> params) {
        if (StringUtils.equals(departmentId, ISystemConstant.TREE_BASE_ROOT_ID_VALUE)) {
            return listUserByExcludeDepartment(params);
        }
        return listUser(departmentId, params);
    }

    private List<String> listGroupUserId(Map<String, Object> params) {
        return departmentUserDao.listGroupUserId(params);
    }

    /**
     * 没有组织机构的用户分页列表
     *
     * @param page
     * @return
     */
    private SuccessResultList<List<DepartmentUserDTO>> listPageUserByExcludeDepartment(ListPage page) {
        List<DepartmentUserDTO> hasDepartmentUsers = list(getHashMap(0));
        List<String> userIds = new ArrayList<>();
        for (DepartmentUserDTO hasDepartmentUserId : hasDepartmentUsers) {
            userIds.add(hasDepartmentUserId.getUserId());
        }
        SuccessResultList<List<UserDTO>> successResultList = userBaseService.listPageByExcludeIds(userIds, page);
        return listPageExcludeDepartmentUser(successResultList);
    }

    /**
     * 没有组织机构的用户分页列表
     *
     * @param params
     * @return
     */
    private List<DepartmentUserDTO> listUserByExcludeDepartment(Map<String, Object> params) {
        List<DepartmentUserDTO> hasDepartmentUsers = list(getHashMap(0));
        List<String> userIds = new ArrayList<>();
        for (DepartmentUserDTO hasDepartmentUserId : hasDepartmentUsers) {
            userIds.add(hasDepartmentUserId.getUserId());
        }
        List<UserDTO> userDTOs = userBaseService.listByExcludeIds(userIds, params);
        return listExcludeDepartmentUser(userDTOs);
    }

    /**
     * 组织机构的用户分页列表
     *
     * @param departmentId 组织机构ID
     * @param page
     * @return
     */
    private SuccessResultList<List<DepartmentUserDTO>> listPageUser(String departmentId, ListPage page) {
        page.getParams().put("departmentId", departmentId);
        page.getParams().put("sort", "userSort");
        page.getParams().put("order", "asc");
        PageHelper.startPage(page.getPage(), page.getRows());
        List<DepartmentUserDTO> departmentUserDTOS = departmentUserDao.listDepartmentUser(page.getParams());
        PageInfo<DepartmentUserDTO> pageInfo = new PageInfo<>(departmentUserDTOS);
        return new SuccessResultList<>(departmentUserDTOS, pageInfo.getPageNum(), pageInfo.getTotal());
    }

    /**
     * 用户列表
     *
     * @param departmentId 部门ID
     * @param params
     * @return
     */
    private List<DepartmentUserDTO> listUser(String departmentId, Map<String, Object> params) {
        List<DepartmentUserDTO> hasDepartmentUsers = list(departmentId);
        if (hasDepartmentUsers.isEmpty()) {
            return new ArrayList<>();
        }
        List<String> userIds = new ArrayList<>();
        for (DepartmentUserDTO hasDepartmentUserId : hasDepartmentUsers) {
            userIds.add(hasDepartmentUserId.getUserId());
        }
        List<UserDTO> userDTOs = userBaseService.listByIds(userIds, params);
        return listDepartmentUser(userDTOs, hasDepartmentUsers);
    }

    @Override
    public SuccessResultList<List<DepartmentUserDTO>> listPageExcludeDepartmentUser(SuccessResultList<List<UserDTO>> successResultList) {
        // 查询用户排序
        List<UserDTO> userDTOs = successResultList.getRows();
        List<DepartmentUserDTO> departmentUserDTOs = listExcludeDepartmentUser(userDTOs);
        return new SuccessResultList<>(departmentUserDTOs, successResultList.getPage(), successResultList.getTotal());
    }

    @Override
    public List<DepartmentUserDTO> listExcludeDepartmentUser(List<UserDTO> userDTOs) {
        // 查询用户排序
        List<DepartmentUserDTO> departmentUserDTOs = new ArrayList<>();
        for (UserDTO userDTO : userDTOs) {
            DepartmentUserDTO departmentUserDTO = new DepartmentUserDTO(userDTO);
            departmentUserDTO.setDepartmentId("");
            departmentUserDTO.setUserSort("ZZZ-000");
            departmentUserDTOs.add(departmentUserDTO);
        }
        return departmentUserDTOs;
    }

    @Override
    public SuccessResultList<List<DepartmentUserDTO>> listPageDepartmentUser(SuccessResultList<List<UserDTO>> successResultList, List<DepartmentUserDTO> hasDepartmentUsers) {
        // 查询用户排序
        List<UserDTO> userDTOs = successResultList.getRows();
        List<DepartmentUserDTO> departmentUserDTOs = listDepartmentUser(userDTOs, hasDepartmentUsers);
        return new SuccessResultList<>(departmentUserDTOs, successResultList.getPage(), successResultList.getTotal());
    }

    /**
     * 部门用户列表
     *
     * @param userDTOs
     * @param hasDepartmentUsers
     * @return
     */
    private List<DepartmentUserDTO> listDepartmentUser(List<UserDTO> userDTOs, List<DepartmentUserDTO> hasDepartmentUsers) {
        // 查询用户排序
        List<DepartmentUserDTO> departmentUserDTOs = new ArrayList<>();
        for (DepartmentUserDTO hasDepartmentUserDTO : hasDepartmentUsers) {
            for (UserDTO userDTO : userDTOs) {
                if (StringUtils.equals(userDTO.getUserId(), hasDepartmentUserDTO.getUserId())) {
                    DepartmentUserDTO departmentUserDTO = new DepartmentUserDTO(userDTO);
                    departmentUserDTO.setDepartmentId(hasDepartmentUserDTO.getDepartmentId());
                    departmentUserDTO.setUserSort(hasDepartmentUserDTO.getUserSort());
                    departmentUserDTOs.add(departmentUserDTO);
                }
            }
        }
        return departmentUserDTOs;
    }

    @Override
    public void setUser(List<DepartmentUserDTO> departmentUserDTOs) {
        if (departmentUserDTOs.isEmpty()) {
            return;
        }
        Set<String> userIdSet = new HashSet<>();
        for (DepartmentUserDTO hasDepartmentUserId : departmentUserDTOs) {
            userIdSet.add(hasDepartmentUserId.getUserId());
        }
        List<UserDTO> userDTOs = userBaseService.listByUserIds(new ArrayList<>(userIdSet));
        for (int i = 0; i < departmentUserDTOs.size(); i++) {
            DepartmentUserDTO departmentUserDTO = departmentUserDTOs.get(i);
            boolean isExist = false;
            for (UserDTO userDTO : userDTOs) {
                if (StringUtils.equals(departmentUserDTO.getUserId(), userDTO.getUserId())) {
                    departmentUserDTO.setUser(userDTO);
                    isExist = true;
                    break;
                }
            }
            if (!isExist) {
                departmentUserDTOs.remove(i);
                i--;
            }
        }
    }

    @Override
    public List<DepartmentDTO> listDepartmentBySelf() {
        List<DepartmentDTO> departmentDTOs = new ArrayList<>();
        List<DepartmentSimpleDTO> departmentSimpleDTOs = securityComponent.getCurrentUser().getDepartments();
        departmentSimpleDTOs.forEach(departmentSimpleDTO -> {
            DepartmentDTO departmentDTO = new DepartmentDTO();
            BeanUtils.copyProperties(departmentSimpleDTO, departmentDTO);
            departmentDTOs.add(departmentDTO);
        });
        return departmentDTOs;
    }

    @Override
    public List<DepartmentDTO> listDepartmentByUserId(String userId) {
        Map<String, Object> params = getHashMap(2);
        params.put("userId", userId);
        List<String> departmentIds = departmentUserDao.listDepartmentId(params);
        if (departmentIds.isEmpty()) {
            return new ArrayList<>();
        }
        return departmentService.listByIds(departmentIds);
    }

    @Override
    public List<UserDTO> listUserByDepartmentId(String departmentId) {
        Map<String, Object> params = getHashMap(2);
        params.put("departmentId", departmentId);
        return departmentUserDao.listUser(params);
    }

    @Override
    public SuccessResultList<List<UserDTO>> listPageUserByDepartmentId(String departmentId, ListPage page) {
        PageHelper.startPage(page.getPage(), page.getRows());
        List<UserDTO> userDTOs = listUserByDepartmentId(departmentId);
        PageInfo<UserDTO> pageInfo = new PageInfo<>(userDTOs);
        return new SuccessResultList<>(userDTOs, pageInfo.getPageNum(), pageInfo.getTotal());
    }

    @Override
    public List<String> listDepartmentIdByUserId(String userId) {
        Map<String, Object> params = getHashMap(2);
        params.put("userId", userId);
        return departmentUserDao.listDepartmentId(params);
    }

    @Override
    public List<String> listDepartmentIdByUserIds(List<String> userIds) {
        if (userIds.isEmpty()) {
            return new ArrayList<>();
        }
        Map<String, Object> params = getHashMap(2);
        params.put("userIds", userIds);
        return departmentUserDao.listDepartmentId(params);
    }

    @Override
    public List<String> listSameDepartmentUserIdByUserId(String userId) {
        Map<String, Object> params = getHashMap(2);
        params.put("userId", userId);
        return departmentUserDao.listSameDepartmentUserId(params);
    }

    @Override
    public List<String> listSameDepartmentUserIdByUserIds(List<String> userIds) {
        Map<String, Object> params = getHashMap(2);
        params.put("userIds", userIds);
        return departmentUserDao.listSameDepartmentUserId(params);
    }

    @Override
    public List<UserDTO> listUser(Map<String, Object> requestParams) {
        requestParams = requestParams == null ? getHashMap(0) : requestParams;
        return departmentUserDao.listUser(requestParams);
    }

    @Override
    public SuccessResultList<List<UserDTO>> listPageUser(ListPage page) {
        PageHelper.startPage(page.getPage(), page.getRows());
        List<UserDTO> userDTOs = listUser(page.getParams());
        PageInfo<UserDTO> pageInfo = new PageInfo<>(userDTOs);
        return new SuccessResultList<>(userDTOs, pageInfo.getPageNum(), pageInfo.getTotal());
    }

    @Override
    public List<UserDTO> listUserByExcludeDepartmentId(String excludeDepartmentId) {
        Map<String, Object> params = getHashMap(2);
        params.put("excludeDepartmentId", excludeDepartmentId);
        return listUser(params);
    }

    @Override
    public List<UserDTO> listUserByExcludeDepartmentIds(List<String> excludeDepartmentIds) {
        Map<String, Object> params = getHashMap(2);
        params.put("excludeDepartmentIds", excludeDepartmentIds);
        return listUser(params);
    }

    @Override
    public SuccessResultList<List<UserDTO>> listPageUserByExcludeDepartmentId(String excludeDepartmentId, ListPage page) {
        page.getParams().put("excludeDepartmentId", excludeDepartmentId);
        return listPageUser(page);
    }

    @Override
    public SuccessResultList<List<UserDTO>> listPageUserByExcludeDepartmentId(List<String> excludeDepartmentIds, ListPage page) {
        page.getParams().put("excludeDepartmentIds", excludeDepartmentIds);
        return listPageUser(page);
    }

    @Override
    public DepartmentContainUserDTO getDepartmentContainUserAndSubByDepartmentId(String departmentId) {
        // 如果是根节点
        if (StringUtils.equals(departmentId, ISystemConstant.TREE_BASE_ROOT_ID_VALUE)) {
            DepartmentContainUserDTO departmentContainUserDTO = new DepartmentContainUserDTO();
            departmentContainUserDTO.setDepartmentId("0");
            departmentContainUserDTO.setDepartmentParentId("-1");
            departmentContainUserDTO.setDepartmentName("根节点");
            departmentContainUserDTO.setDepartmentCode("");
            departmentContainUserDTO.setSubDepartments(departmentService.listByParentId(ISystemConstant.TREE_BASE_ROOT_ID_VALUE));
            return departmentContainUserDTO;
        }
        // 不是根节点
        DepartmentPO departmentPO = departmentService.getPO(departmentId);
        if (departmentPO == null) {
            throw new SearchException("部门不存在");
        }
        DepartmentContainUserDTO departmentContainUserDTO = new DepartmentContainUserDTO();
        departmentContainUserDTO.setDepartmentId(departmentPO.getDepartmentId());
        departmentContainUserDTO.setDepartmentParentId(departmentPO.getDepartmentParentId());
        departmentContainUserDTO.setDepartmentName(departmentPO.getDepartmentName());
        departmentContainUserDTO.setDepartmentCode(departmentPO.getDepartmentCode());
        departmentContainUserDTO.setSubDepartments(departmentService.listByParentId(departmentPO.getDepartmentId()));
        departmentContainUserDTO.setUsers(listUserByDepartmentId(departmentPO.getDepartmentId()));
        return departmentContainUserDTO;
    }

    @Override
    public List<UserPO> listUserPO(Map<String, Object> params) {
        params = params == null ? getHashMap(0) : params;
        return departmentUserDao.listUserPO(params);
    }

    @Override
    public List<UserPO> listUserPOByDepartmentId(String departmentId) {
        Map<String, Object> params = getHashMap(2);
        params.put("departmentId", departmentId);
        return listUserPO(params);
    }

    @Override
    public List<UserPO> listUserPOByDepartmentIds(List<String> departmentIds) {
        if (departmentIds == null || departmentIds.isEmpty()) {
            return new ArrayList<>();
        }
        Map<String, Object> params = getHashMap(2);
        params.put("departmentIds", departmentIds);
        return listUserPO(params);
    }

    /**
     * 更新 mongo
     *
     * @param departmentUserIds
     */
    private void updateMongoLoginUser(List<String> departmentUserIds) {
        if (mongoLoginUserService != null) {
            CachedThreadPoolUtil.execute(() -> {
                mongoLoginUserService.updateByUserIds(departmentUserIds);
            });
        }
    }
}
