package com.hz.pm.api.organization.manage;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.ningdatech.basic.model.PageVo;
import com.hz.pm.api.common.config.DingOrganizationProperties;
import com.hz.pm.api.common.helper.RegionCacheHelper;
import com.hz.pm.api.common.util.StrUtils;
import com.hz.pm.api.ding.constants.DingOrganizationContant;
import com.hz.pm.api.fiscal.service.ICompanyFiscalCodeService;
import com.hz.pm.api.organization.model.entity.DingEmployeeInfo;
import com.hz.pm.api.organization.model.entity.DingOrganization;
import com.hz.pm.api.organization.model.po.ReqOrganizationListPO;
import com.hz.pm.api.organization.model.po.ReqSynthesizePO;
import com.hz.pm.api.organization.model.vo.KeyTreeVO;
import com.hz.pm.api.organization.model.vo.OrganizationTreeVO;
import com.hz.pm.api.organization.model.vo.ResOrganizationListVO;
import com.hz.pm.api.organization.service.IDingEmployeeInfoService;
import com.hz.pm.api.organization.service.IDingOrganizationService;
import com.hz.pm.api.sys.model.dto.RegionDTO;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author liuxinxin
 * @date 2023/1/13 下午2:55
 */
@Component
@RequiredArgsConstructor
public class OrganizationManage {

    private final IDingOrganizationService iDingOrganizationService;

    private final DingOrganizationProperties dingOrganizationProperties;

    private final IDingEmployeeInfoService iDingEmployeeInfoService;

    private final RegionCacheHelper regionCacheHelper;

    private final ICompanyFiscalCodeService iCompanyFiscalCodeService;

    public PageVo<ResOrganizationListVO> organizationList(ReqOrganizationListPO reqOrganizationListPO) {
        String orgName = reqOrganizationListPO.getOrgName();
        Boolean onlyUnit = reqOrganizationListPO.getOnlyUnit();
        String regionId = reqOrganizationListPO.getRegionId();

        Page<DingOrganization> page = iDingOrganizationService
                .page(new Page<>(reqOrganizationListPO.getPageNumber(), reqOrganizationListPO.getPageSize())
                        , Wrappers.lambdaQuery(DingOrganization.class)
                                .like(StringUtils.isNotBlank(orgName), DingOrganization::getOrganizationName, orgName)
                                .eq(StringUtils.isNotBlank(regionId), DingOrganization::getDivisionCode, regionId)
                                .notIn(onlyUnit, DingOrganization::getTypeCode, "GOV_INTERNAL_INSTITUTION")
                                .orderByAsc(DingOrganization::getId)
                );

        long total = page.getTotal();
        List<DingOrganization> records = page.getRecords();
        List<ResOrganizationListVO> resVOList = new ArrayList<>();
        if (CollUtil.isNotEmpty(records)) {
            List<String> organizationCodeList = records.stream().map(DingOrganization::getOrganizationCode)
                    .distinct().collect(Collectors.toList());
            Map<String, String> orgFiscalCodeMap = iCompanyFiscalCodeService.getByOrgFiscalCodeMap(organizationCodeList);

            resVOList = records.stream().map(r -> {
                ResOrganizationListVO resOrganizationListVO = new ResOrganizationListVO();
                resOrganizationListVO.setOrgCode(r.getOrganizationCode());
                resOrganizationListVO.setOrgName(r.getOrganizationName());
                String divisionCode = r.getDivisionCode();
                if (StringUtils.isNotBlank(divisionCode)) {
                    RegionDTO regionDTO = regionCacheHelper.getByCodeAndLevel(divisionCode, 3);
                    resOrganizationListVO.setRegionId(regionDTO.getRegionCode());
                    resOrganizationListVO.setRegionName(regionDTO.getRegionName());
                }
                String fiscalCode = orgFiscalCodeMap.get(r.getOrganizationCode());
                resOrganizationListVO.setFiscalCode(fiscalCode);
                return resOrganizationListVO;
            }).collect(Collectors.toList());
        }

        PageVo<ResOrganizationListVO> pageVo = new PageVo<>();
        pageVo.setTotal(total);
        pageVo.setRecords(resVOList);
        return pageVo;
    }

    public List<OrganizationTreeVO> getChildOrganizationList(String parentCode, String orgName, Boolean onlyUnit) {
        List<String> parentCodeList;
        List<DingOrganization> dingOrganizationList;
        if (StrUtils.isBlank(parentCode)) {
            parentCodeList = dingOrganizationProperties.getDeptVisibleScopes();
            dingOrganizationList = iDingOrganizationService.list(Wrappers.lambdaQuery(DingOrganization.class)
                    .like(StringUtils.isNotBlank(orgName), DingOrganization::getOrganizationName, orgName)
                    .notIn(onlyUnit, DingOrganization::getTypeCode, "GOV_INTERNAL_INSTITUTION")
                    .in(DingOrganization::getOrganizationCode, parentCodeList));
        } else {
            parentCodeList = CollectionUtil.toList(parentCode);
            dingOrganizationList = iDingOrganizationService
                    .list(Wrappers.lambdaQuery(DingOrganization.class)
                            .like(StringUtils.isNotBlank(orgName), DingOrganization::getOrganizationName, orgName)
                            .notIn(onlyUnit, DingOrganization::getTypeCode, "GOV_INTERNAL_INSTITUTION")
                            .in(DingOrganization::getParentCode, parentCodeList));
        }

        if (CollectionUtils.isEmpty(dingOrganizationList)) {
            return new ArrayList<>();
        }

        dingOrganizationList.sort(Comparator.comparing(DingOrganization::getDisplayOrder));
        return dingOrganizationList.stream().map(r -> {
            OrganizationTreeVO treeVO = new OrganizationTreeVO();
            treeVO.setId(r.getId());
            treeVO.setName(r.getOrganizationName());
//            Boolean enabled = "1".equals(r.get());
//            treeVO.setEnabled(enabled);
            treeVO.setOrganizationCode(r.getOrganizationCode());
            treeVO.setParentCode(r.getParentCode());
//            treeVO.setSubCount(r.get());
//            Boolean isLeaf = true;
//            Long subCount = r.getSubCount();
//            if (Objects.nonNull(subCount) && subCount > 0) {
//                isLeaf = false;
//            }
//            treeVO.setIsLeaf(isLeaf);
//            treeVO.setDeptSort(r.getDeptSort());
//            treeVO.setUnionCode(r.getName() + "##" + r.getOrganizationCode());
            return treeVO;
        }).collect(Collectors.toList());
    }

    public List<KeyTreeVO> treeRubbishVOList(ReqSynthesizePO request) {
        String organizationCode = request.getOrganizationCode();
        String organizationName = request.getOrganizationName();
        String employeeName = request.getEmployeeName();
        Boolean onlyUnit = request.getOnlyUnit();

        // 用户搜索为特殊逻辑
        if (StringUtils.isNotBlank(employeeName)) {
            return treeEmployeeQuery(employeeName, organizationCode);
        }

        List<DingOrganization> dingOrganizationList = new ArrayList<>();
        List<String> organizationCodeList = new ArrayList<>();
        if (StringUtils.isNotBlank(organizationName)) {
            dingOrganizationList = iDingOrganizationService.list(Wrappers.lambdaQuery(DingOrganization.class)
                    .like(DingOrganization::getOrganizationName, organizationName)
                    .in(onlyUnit, DingOrganization::getTypeCode, Lists.newArrayList(DingOrganizationContant.UNIT_TYPE,
                            DingOrganizationContant.HOLLOW)));
            if (dingOrganizationList.isEmpty()) {
                return new ArrayList<>();
            }
        } else if (StrUtils.isBlank(organizationCode)) {
            organizationCodeList = dingOrganizationProperties.getDeptVisibleScopes();
        } else {
            organizationCodeList = CollectionUtil.toList(organizationCode);
        }

        if (CollectionUtil.isEmpty(dingOrganizationList)) {
            dingOrganizationList = iDingOrganizationService.list(Wrappers.lambdaQuery(DingOrganization.class)
                    .in(DingOrganization::getOrganizationCode, organizationCodeList)
                    .notIn(onlyUnit, DingOrganization::getTypeCode, "GOV_INTERNAL_INSTITUTION"));
        }

        List<KeyTreeVO> orgKeyTreeVOList = dingOrganizationList.stream().map(r -> {
            KeyTreeVO keyTreeVO = new KeyTreeVO();
            keyTreeVO.setTitle(r.getOrganizationName());
            keyTreeVO.setKey(r.getOrganizationCode());
            keyTreeVO.setType("ORGANIZATION");
            return keyTreeVO;
        }).collect(Collectors.toList());
        treeVOList(request.getNeedMember(), orgKeyTreeVOList, onlyUnit);
        return orgKeyTreeVOList;
    }

    public List<KeyTreeVO> treeEmployeeQuery(String employeeName, String organizationCode) {
        List<String> parentCodeList = CollUtil.toList(organizationCode).stream()
                .filter(StringUtils::isNotBlank)
                .collect(Collectors.toList());

        // 获取所有的组织列表
        List<String> organizationCodeList = new ArrayList<>();
        getChildList(organizationCodeList, parentCodeList);
        organizationCodeList = organizationCodeList.stream().distinct().collect(Collectors.toList());

        List<DingEmployeeInfo> dingEmployeeInfoList = iDingEmployeeInfoService
                .list(Wrappers.lambdaQuery(DingEmployeeInfo.class)
                        .like(DingEmployeeInfo::getEmployeeName, employeeName)
                        .eq(DingEmployeeInfo::getMainJob, "true")
                        .in(CollUtil.isNotEmpty(organizationCodeList), DingEmployeeInfo::getOrganizationCode, organizationCodeList)
                );
        List<String> resultOrganizationCodeList = dingEmployeeInfoList.stream()
                .filter(r -> StringUtils.isNotBlank(r.getOrganizationCode()))
                .map(DingEmployeeInfo::getOrganizationCode)
                .distinct().collect(Collectors.toList());

        if (CollectionUtil.isEmpty(resultOrganizationCodeList)) {
            return new ArrayList<>();
        }

        List<DingOrganization> dingOrganizationList = iDingOrganizationService.list(Wrappers.lambdaQuery(DingOrganization.class)
                .in(DingOrganization::getOrganizationCode, resultOrganizationCodeList));

        List<KeyTreeVO> orgKeyTreeVOList = dingOrganizationList.stream().map(r -> {
            KeyTreeVO keyTreeVO = new KeyTreeVO();
            keyTreeVO.setTitle(r.getOrganizationName());
            keyTreeVO.setKey(r.getOrganizationCode());
            keyTreeVO.setType("ORGANIZATION");
            return keyTreeVO;
        }).collect(Collectors.toList());

        employeeNameSearcheTreeVOList(orgKeyTreeVOList, dingEmployeeInfoList);
        return orgKeyTreeVOList;
    }

    private void getChildList(List<String> orgCodeList, List<String> parentCodeList) {
        if (CollUtil.isEmpty(parentCodeList)) {
            return;
        }
        orgCodeList.addAll(parentCodeList);
//        orgCodeList = orgCodeList.stream().distinct().collect(Collectors.toList());

        for (String parentCode : parentCodeList) {
            List<DingOrganization> childOrgList = iDingOrganizationService.list(Wrappers.lambdaQuery(DingOrganization.class)
                    .in(DingOrganization::getParentCode, parentCode));
            List<String> newParentCodeList = childOrgList.stream().map(DingOrganization::getOrganizationCode).collect(Collectors.toList());
            getChildList(orgCodeList, newParentCodeList);
        }
    }

    private void employeeNameSearcheTreeVOList(List<KeyTreeVO> basicOrgKeyTreeVOList, List<DingEmployeeInfo> allDingEmployeeInfoList) {
        Map<String, List<DingEmployeeInfo>> orgCodeEmployeeMap = allDingEmployeeInfoList.stream()
                .filter(r -> StringUtils.isNotBlank(r.getOrganizationCode()))
                .collect(Collectors.groupingBy(DingEmployeeInfo::getOrganizationCode));

        for (KeyTreeVO basicOrgKeyTreeVO : basicOrgKeyTreeVOList) {
            String parentCode = basicOrgKeyTreeVO.getKey();

            List<DingEmployeeInfo> dingEmployeeInfoList = orgCodeEmployeeMap.get(parentCode);
            List<KeyTreeVO> memberChildren = dingEmployeeInfoList.stream().map(r -> {
                KeyTreeVO child = new KeyTreeVO();
                child.setKey(r.getEmployeeCode());
                child.setTitle(r.getEmployeeName());
                child.setType("MEMBER");
                return child;
            }).collect(Collectors.toList());
            basicOrgKeyTreeVO.setChildren(memberChildren);
        }
    }


    public void treeVOList(Boolean needMember, List<KeyTreeVO> basicOrgKeyTreeVOList, Boolean onlyUnit) {
        for (KeyTreeVO basicOrgKeyTreeVO : basicOrgKeyTreeVOList) {
            String parentCode = basicOrgKeyTreeVO.getKey();
            List<OrganizationTreeVO> childOrganizationList = getChildOrganizationList(parentCode, null, onlyUnit);

            List<KeyTreeVO> orgKeyTreeVOList = childOrganizationList.stream().map(r -> {
                KeyTreeVO keyTreeVO = new KeyTreeVO();
                keyTreeVO.setTitle(r.getName());
                keyTreeVO.setKey(r.getOrganizationCode());
                keyTreeVO.setType("ORGANIZATION");
                return keyTreeVO;
            }).collect(Collectors.toList());

            if (StringUtils.isNotBlank(parentCode) && needMember) {
                List<DingEmployeeInfo> dingEmployeeInfoList = iDingEmployeeInfoService.list(Wrappers.lambdaQuery(DingEmployeeInfo.class)
                        .eq(DingEmployeeInfo::getMainJob, "true")
                        .eq(DingEmployeeInfo::getOrganizationCode, parentCode));

                List<KeyTreeVO> memberChildren = dingEmployeeInfoList.stream().map(r -> {
                    KeyTreeVO child = new KeyTreeVO();
                    child.setKey(r.getEmployeeCode());
                    child.setTitle(r.getEmployeeName());
                    child.setType("MEMBER");
                    return child;
                }).collect(Collectors.toList());

                if (CollUtil.isNotEmpty(memberChildren)) {
                    orgKeyTreeVOList.addAll(memberChildren);
                }
            }
            basicOrgKeyTreeVO.setChildren(orgKeyTreeVOList);
        }
    }


}
