package com.cmeeting.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.util.StrUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cmeeting.ad.entity.SysUserSync;
import com.cmeeting.constant.CategoryConstant;
import com.cmeeting.constant.PermissionPruposeType;
import com.cmeeting.constant.RecordTemplateConstant;
import com.cmeeting.constant.UserTypeConstant;
import com.cmeeting.dto.PermissionCheckedDTO;
import com.cmeeting.dto.SysUserSyncDTO;
import com.cmeeting.mapper.primary.SysUserSyncCategoryMapper;
import com.cmeeting.mapper.primary.SysUserSyncMapper;
import com.cmeeting.pojo.ModulePermission;
import com.cmeeting.pojo.SysUserSyncCategory;
import com.cmeeting.service.ISysUserSyncCategoryService;
import com.cmeeting.service.ModulePermissionService;
import com.cmeeting.service.SysUserSyncService;
import com.cmeeting.util.CategoryTreeUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.net.URLEncoder;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class SysUserSyncServiceImpl extends ServiceImpl<SysUserSyncMapper, SysUserSync> implements SysUserSyncService {

    @Resource
    private ISysUserSyncCategoryService iSysUserSyncCategoryService;
    @Resource
    private SysUserSyncCategoryMapper sysUserSyncCategoryMapper;
    @Resource
    private ModulePermissionService modulePermissionService;

    private static Map<String, String> DEPT_MAP = new HashMap<>(12);

    static {
        DEPT_MAP.put("10340", "集团总部");
        DEPT_MAP.put("602700", "能化板块");
        DEPT_MAP.put("616859", "空港板块");
        DEPT_MAP.put("616766", "集装箱集团");
        DEPT_MAP.put("616844", "车辆板块");
        DEPT_MAP.put("616860", "海工板块");
        DEPT_MAP.put("616861", "产城板块");
        DEPT_MAP.put("640071", "物流板块");
        DEPT_MAP.put("617560", "融资租赁贵公司");
        DEPT_MAP.put("640075", "财务公司");
        DEPT_MAP.put("641858", "其他类型企业");
        DEPT_MAP.put("707435", "集团创新企业");
        DEPT_MAP.put("686701", "中集海工");
        DEPT_MAP.put("710972", "中集资本");
        DEPT_MAP.put("711091", "中集载具");
        DEPT_MAP.put("698023", "中集同创");
    }

    @Override
    public String getDeptPathByUserId(String userId) {
        SysUserSync sysUserSync = baseMapper.selectOne(new LambdaQueryWrapper<SysUserSync>()
                .eq(SysUserSync::getUserId, userId)
                .select(SysUserSync::getDeptId).last("limit 1"));
        String deptId = sysUserSync.getDeptId();
        return getDeptPath("/" + deptId, deptId);
    }

    @Override
    public List<String> getDeptPathByUserIdAndInSet(String userId) {
        List<SysUserSync> sysUserSyncs = baseMapper.selectList(new LambdaQueryWrapper<SysUserSync>()
                .eq(SysUserSync::getUserId, userId)
                .select(SysUserSync::getDeptId));
        List<String> collect = sysUserSyncs.stream().map(SysUserSync::getDeptId).collect(Collectors.toList());
        List<String> ret = new ArrayList<>();
        for (String s : collect) {
            ret.add(getDeptPath("/" + s, s));
        }
        return ret;
    }

    /**
     * 向上获取某个部门的路径
     *
     * @param deptId
     */
    private String getDeptPath(String deptPath, String deptId) {
        String parentDeptId = baseMapper.getParentDeptId(deptId);
        if (StringUtils.isEmpty(parentDeptId)) return deptPath;

        return getDeptPath("/" + parentDeptId + deptPath, parentDeptId);
    }

    public String getDeptPathName(String path, String deptId) {
        if (StrUtil.isBlank(deptId) || CategoryConstant.ROOT_ID.equals(deptId)) {
            return path;
        }
        SysUserSyncCategory sysUserSyncCategory = iSysUserSyncCategoryService.getOne(new LambdaQueryWrapper<SysUserSyncCategory>()
                .eq(SysUserSyncCategory::getDeptId, deptId)
                .select(SysUserSyncCategory::getDeptId, SysUserSyncCategory::getName, SysUserSyncCategory::getParentId)
                .last("limit 1"));
        if (sysUserSyncCategory == null) {
            return path;
        }

        return getDeptPathName("/" + sysUserSyncCategory.getName() + path, sysUserSyncCategory.getParentId());
    }


    /**
     * 向上获取部门集合，包含当前部门
     *
     * @return
     */
    @Override
    public List<SysUserSyncCategory> getCategoryListByUserId(String userId) {
        List<SysUserSync> sysUserSyncs = baseMapper.selectList(new LambdaQueryWrapper<SysUserSync>().eq(SysUserSync::getUserId, userId));
        List<SysUserSyncCategory> categoryList = new ArrayList<>();
        for (SysUserSync sysUserSync : sysUserSyncs) {
            String deptId = sysUserSync.getDeptId();
            // 获取当前租户所有部门
            getParentCategoryList(deptId, categoryList);
        }
        return categoryList;
    }

    private void getParentCategoryList(String deptId, List<SysUserSyncCategory> categoryList) {
        if (CategoryConstant.ROOT_ID.equals(deptId)) {
            return;
        }
        SysUserSyncCategory category = sysUserSyncCategoryMapper.selectOne(new LambdaQueryWrapper<SysUserSyncCategory>()
                .eq(SysUserSyncCategory::getDeptId, deptId)
        );
        if (ObjectUtils.isEmpty(category)) {
            return;
        }
        categoryList.add(category);
        getParentCategoryList(category.getParentId(), categoryList);
    }


    @Override
    public PermissionCheckedDTO listByCategoryId(String categoryId, String search, List<String> categoryList, List<String> userList) {
        PermissionCheckedDTO dto = new PermissionCheckedDTO();
        // 顶层分类查询所有parentId不存在的分类及用户
        List<String> noExitParentIds = new ArrayList<>();
        List<String> childrenDeptIds = new ArrayList<>();

        List<SysUserSyncCategory> categories = iSysUserSyncCategoryService.list(new LambdaQueryWrapper<>());
        if (CategoryConstant.ROOT.equals(categoryId)) {
            // 查询分类为ROOT即查询所有找不到parentId的分类
            Set<String> map = categories.stream().map(SysUserSyncCategory::getDeptId).collect(Collectors.toSet());
            for (SysUserSyncCategory category : categories) {
                if (!map.contains(category.getParentId())) {
                    noExitParentIds.add(category.getDeptId());
                }
            }
        } else if (StrUtil.isNotBlank(categoryId)) {
            Map<String, List<String>> parentMap = categories.stream().collect(Collectors.groupingBy(SysUserSyncCategory::getParentId, Collectors.mapping(SysUserSyncCategory::getDeptId, Collectors.toList())));
            List<String> children = getChildren(parentMap, categoryId);
            childrenDeptIds.add(categoryId);
            childrenDeptIds.addAll(children);
        }
        List<SysUserSyncCategory> list = iSysUserSyncCategoryService.list(new LambdaQueryWrapper<SysUserSyncCategory>()
                .in(StrUtil.isNotBlank(search) && StrUtil.isNotBlank(categoryId) && !CategoryConstant.ROOT.equals(categoryId) && CollUtil.isNotEmpty(childrenDeptIds), SysUserSyncCategory::getDeptId, childrenDeptIds)
                .in(StrUtil.isBlank(search) && CategoryConstant.ROOT.equals(categoryId) && CollUtil.isNotEmpty(noExitParentIds), SysUserSyncCategory::getDeptId, noExitParentIds)
                .eq(StrUtil.isBlank(search) && StrUtil.isNotBlank(categoryId) && !CategoryConstant.ROOT.equals(categoryId), SysUserSyncCategory::getParentId, categoryId)
                .like(StrUtil.isNotBlank(search), SysUserSyncCategory::getName, search)
                .in(CollUtil.isNotEmpty(categoryList), SysUserSyncCategory::getDeptId, categoryList) // 指定分类
                .select(SysUserSyncCategory::getDeptId, SysUserSyncCategory::getName));

        List<PermissionCheckedDTO.Category> cates = new ArrayList<>();
        list.forEach(ca -> {
            PermissionCheckedDTO.Category category = new PermissionCheckedDTO.Category();
            category.setId(ca.getDeptId());
            category.setName(ca.getName());
            category.setUserType(UserTypeConstant.SYNC);
            cates.add(category);
        });
        dto.setCategoryList(cates);

        List<PermissionCheckedDTO.User> users;
        if (StrUtil.isNotBlank(search)) {
            if (CategoryConstant.ROOT_ID.equals(categoryId)) {
                users = baseMapper.findName(null, null, search, null);
            } else {
                users = baseMapper.findName(childrenDeptIds, null, search, null);
            }
        } else {
            List<String> deptIds = categories.stream().map(SysUserSyncCategory::getDeptId).collect(Collectors.toList());
            if (CategoryConstant.ROOT_ID.equals(categoryId)) {
                List<SysUserSync> sysUserSyncList = this.list(new LambdaQueryWrapper<SysUserSync>()
                        .notIn(CollUtil.isNotEmpty(deptIds), SysUserSync::getDeptId, deptIds)
                        .select(SysUserSync::getUserId));
                if (CollUtil.isNotEmpty(sysUserSyncList)) {
                    List<String> sysUserSyncIdList = sysUserSyncList.stream().map(SysUserSync::getUserId).collect(Collectors.toList());
                    userList.addAll(sysUserSyncIdList);
                }
                if (CollUtil.isNotEmpty(userList)) {
                    users = baseMapper.findName(null, null, search, userList);
                } else {
                    users = new ArrayList<>();
                }
            } else {
                users = baseMapper.findName(null, categoryId, search, userList);
            }
        }
        if (CollUtil.isNotEmpty(users)) {
            for (PermissionCheckedDTO.User user : users) {
                user.setUserType(UserTypeConstant.SYNC);
            }
        }
        dto.setUserList(users);
        return dto;
    }

    @Override
    public List<PermissionCheckedDTO.User> findInUserIdsOrShareCateIds(List<String> userIds, List<String> shareCateIds, String search) {
        return baseMapper.findInUserIdsOrShareCateIds(userIds, shareCateIds, search);
    }

    @Override
    public List<PermissionCheckedDTO.User> findByParam(List<String> userIds, List<String> notInCateIds, List<String> shareCateIds, String search, String categoryId) {
        return baseMapper.findByParam(userIds, notInCateIds, shareCateIds, search, categoryId);
    }

    @Override
    public Page<SysUserSyncDTO> selectPage(Integer current, Integer size, String deptId, String search) {
        Page page = new Page(current, size);
        List<String> deptIds = new ArrayList<>();
        if (StrUtil.isNotBlank(deptId) && !deptId.equals(CategoryTreeUtil.ALL)) {
            deptIds.add(deptId);
            List<SysUserSyncCategory> categoryList = iSysUserSyncCategoryService.list(new LambdaQueryWrapper<SysUserSyncCategory>()
                    .select(SysUserSyncCategory::getDeptId, SysUserSyncCategory::getParentId));
            Map<String, List<String>> collect = categoryList.stream()
                    .collect(Collectors.groupingBy(SysUserSyncCategory::getParentId, Collectors.mapping(SysUserSyncCategory::getDeptId, Collectors.toCollection(ArrayList::new))));
            deptIds.addAll(getChildren(collect, deptId));
        }
        Page<SysUserSyncDTO> retPage = baseMapper.selectByDeptId(deptIds, page, search);
        List<SysUserSyncDTO> records = retPage.getRecords();
        if (CollUtil.isNotEmpty(records)) {
            List<ModulePermission> list = modulePermissionService.list(new LambdaQueryWrapper<ModulePermission>()
                    .eq(ModulePermission::getType, RecordTemplateConstant.REL_TYPE_USER)
                    .eq(ModulePermission::getUserType, UserTypeConstant.SYNC)
                    .eq(ModulePermission::getPurpose, PermissionPruposeType.PERSONAL_CLOSE)
                    .in(ModulePermission::getRelId, records.stream().map(SysUserSyncDTO::getUserId).collect(Collectors.toList()))
                    .select(ModulePermission::getRelId)
            );
            Set<String> set = list.stream().map(ModulePermission::getRelId).collect(Collectors.toSet());
            for (SysUserSyncDTO record : records) {
                if (set.contains(record.getUserId())) {
                    record.setEnable(false);
                }
            }
        }
        return retPage;
    }

    @Override
    public List<SysUserSync> listByUserIds(List<String> userIdList, String search) {
        return baseMapper.listByUserIds(userIdList, search);
    }

    private List<String> getChildren(Map<String, List<String>> collect, String deptId) {
        List<String> ids = new ArrayList<>();
        if (collect.containsKey(deptId)) {
            List<String> strings = collect.get(deptId);
            ids.addAll(strings);
            for (String string : strings) {
                ids.addAll(getChildren(collect, string));
            }
        }
        return ids;
    }

    @Override
    public List<SysUserSyncCategory> getTreeList() {
        int companyIndex = 2;
        List<Tree<String>> list = iSysUserSyncCategoryService.tree();
        Tree<String> tree = list.get(0);
        List<SysUserSyncCategory> categoryList = new ArrayList<>();
        getList(companyIndex, categoryList, tree.getChildren(), "");
        return categoryList;
    }

    @Override
    public void downloadTree(List<SysUserSyncCategory> list, HttpServletResponse response) {
        List<String> headList = CollUtil.newArrayList("/版块/一级/二级");
        ServletOutputStream outputStream = null;
        // 导出
        ExcelWriter writer = ExcelUtil.getWriter(true);
        try {
            List<List<String>> rows = new ArrayList<>();
            for (SysUserSyncCategory sysUserSyncCategory : list) {
                rows.add(CollUtil.newArrayList(sysUserSyncCategory.getPath()));
            }
            writer.setColumnWidth(0, 100);
            writer.writeHeadRow(headList);
            writer.write(rows, true);
            String fileName = String.format("分级导出%s.xlsx", DateUtil.today());
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "utf8"));
            outputStream = response.getOutputStream();
            writer.flush(outputStream);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            writer.close();
            IoUtil.close(outputStream);
        }
    }

    private void getList(int companyIndex, List<SysUserSyncCategory> list, List<Tree<String>> children, String pre) {
        if (CollUtil.isNotEmpty(children)) {
            for (Tree<String> child : children) {
                if (companyIndex == 0) {
                    if (CollUtil.isNotEmpty(child.getChildren())) {
                        for (Tree<String> childChild : child.getChildren()) {
                            SysUserSyncCategory cate = SysUserSyncCategory.builder().deptId(childChild.getId()).name(childChild.getName().toString()).path(pre + "/" + child.getName().toString() + "/" + childChild.getName().toString()).build();
                            list.add(cate);
                        }
                    } else {
                        SysUserSyncCategory cate = SysUserSyncCategory.builder().deptId(child.getId()).name(child.getName().toString()).path(pre + "/" + child.getName().toString()).build();
                        list.add(cate);
                    }
                }
                getList(companyIndex - 1, list, child.getChildren(), pre + "/" + child.getName());
            }
        }
    }

}
