package com.infoepoch.pms.agent.domain.baisc.organization;

import com.fasterxml.jackson.core.type.TypeReference;
import com.infoepoch.pms.agent.common.utils.ApplicationContextTool;
import com.infoepoch.pms.agent.common.utils.OrganizationTool;
import com.infoepoch.pms.agent.common.utils.RedisKeys;
import com.infoepoch.pms.agent.common.utils.StringTool;
import com.infoepoch.pms.agent.common.utils.component.RedisTool;
import com.infoepoch.pms.agent.config.JsonUtils;
import com.infoepoch.pms.agent.platform.shared.exception.ValidationException;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 组织根
 */
@Component
public class OrganizationRoot {

    private OrganizationRoot() {
    }

    public static void initAll() {
        // 数据放入redis
        RedisTool redisTool = (RedisTool) ApplicationContextTool.getBean("redisTool");
        IOrganizationRepository repository = (IOrganizationRepository) ApplicationContextTool.getBean("organizationRepository");
        List<Organization> rootOrganizations = repository.selectByParentId("0");
        // 组织列表数据放入redis
        redisTool.put(RedisKeys.ROOT_ORGANIZATION_LIST, JsonUtils.objectToJson(rootOrganizations), 1, TimeUnit.DAYS);
        Map<String, Organization> organizationMap = repository.selectMapAll();
        for (Organization o : rootOrganizations) {
            init(o, organizationMap);
            List<Organization> children = organizationMap.values().stream()
                    .filter(s -> s.getpId().equals(o.getId()))
                    .filter(s -> !s.isDisabled())
                    .collect(Collectors.toList());
            if (!children.isEmpty()) {
                OrganizationTool.organizationSort(children);
                o.addChildren(children);
            }
        }
        // 组织列表数据放入redis
        redisTool.put(RedisKeys.ORGANIZATION_LIST, JsonUtils.objectToJson(rootOrganizations), 1, TimeUnit.DAYS);
        // 组织MAP数据放入redis
        redisTool.put(RedisKeys.ROOT_ORGANIZATION_MAP, JsonUtils.objectToJson(organizationMap), 1, TimeUnit.DAYS);
    }

    /**
     * @Description: 初始化
     * @Param: [o]
     * @Author: zhangyd
     */
    private static void init(Organization o, Map<String, Organization> organizationMap) {
        List<Organization> children = organizationMap.values().stream().filter(s -> s.getpId().equals(o.getId())).collect(Collectors.toList());
        if (!children.isEmpty()) {
            Organization parentOrg = organizationMap.get(o.getId());
            parentOrg.addChildren(children);
            for (Organization child : children) {
                init(child, organizationMap);
            }
        }
    }

    /**
     * @Description: 刷新组织
     * @Param: []
     * @Author: zhangyd
     */
    public static void fresh() {
        initAll();
    }

    /**
     * 获取根组织列表
     *
     * @return
     */
    public static List<Organization> getRootOrganizationList() {
        RedisTool redisTool = (RedisTool) ApplicationContextTool.getBean("redisTool");
        String rootOrganizationListStr = redisTool.get(RedisKeys.ROOT_ORGANIZATION_LIST);
        if (rootOrganizationListStr == null) {
            initAll();
            rootOrganizationListStr = redisTool.get(RedisKeys.ROOT_ORGANIZATION_LIST);
        }
        return JsonUtils.jsonToList(rootOrganizationListStr, Organization.class);
    }

    /**
     * @return
     */
    public static List<Organization> getOrganizationList() {
        RedisTool redisTool = (RedisTool) ApplicationContextTool.getBean("redisTool");
        String rootOrganizationListStr = redisTool.get(RedisKeys.ORGANIZATION_LIST);
        if (rootOrganizationListStr == null) {
            initAll();
            rootOrganizationListStr = redisTool.get(RedisKeys.ORGANIZATION_LIST);
        }
        return JsonUtils.jsonToList(rootOrganizationListStr, Organization.class);
    }

    /**
     * 获取组织MAP
     *
     * @return
     */
    public static Map<String, Organization> getOrganizationMap() {
        RedisTool redisTool = (RedisTool) ApplicationContextTool.getBean("redisTool");
        String organizationMapStr = redisTool.get(RedisKeys.ROOT_ORGANIZATION_MAP);
        if (organizationMapStr == null) {
            initAll();
            organizationMapStr = redisTool.get(RedisKeys.ROOT_ORGANIZATION_MAP);
        }
        return JsonUtils.jsonToObject(organizationMapStr, new TypeReference<Map<String, Organization>>() {
        });
    }

    /**
     * @param id
     * @return
     */
    public static Organization getOrganizationById(String id) {
        IOrganizationRepository repository = (IOrganizationRepository) ApplicationContextTool.getBean("organizationRepository");
        return repository.selectById(id);
    }

    public static List<Organization> getOrganizationByIds(List<String> ids){
        IOrganizationRepository repository = (IOrganizationRepository) ApplicationContextTool.getBean("organizationRepository");
        return repository.selectByIds(ids);
    }

    /**
     * 获取上级组织ID列表
     *
     * @param organization
     * @return
     */
    public static List<String> getAllParentId(Organization organization) {
        List<String> parentIdList = new ArrayList<>();
        Map<String, Organization> organizationMap = getOrganizationMap();
        Organization parentOrg = organizationMap.get(organization.getpId());
        while (parentOrg != null) {
            parentIdList.add(parentOrg.getId());
            parentOrg = organizationMap.get(parentOrg.getpId());
        }
        return parentIdList;
    }

    /**
     * 获取组织全名
     *
     * @param organization
     * @return
     */
    public static String getOrganizationFullName(Organization organization) {
        StringBuilder sb = new StringBuilder();
        Map<String, Organization> organizationMap = getOrganizationMap();
        Organization parentOrg = organizationMap.get(organization.getpId());
        while (parentOrg != null) {
            sb.insert(0, parentOrg.getShortName() + "\\");
            parentOrg = organizationMap.get(parentOrg.getpId());
        }
        sb.append(organization.getShortName());
        return sb.toString();
    }

    //-------------------------------------------------------------------------

    /**
     * 取所有根组织，根据displayOrder排序
     */
    public static List<Organization> getRootOrganizations() {
        List<Organization> collect = getOrganizationList().stream()
                .sorted(Comparator.comparing(Organization::getDisplayOrderValue))
                .collect(Collectors.toList());
        return collect;
    }

    /**
     * 根据id查找部门组织名称或公司组织名称，未找到返回空字符串
     *
     * @param id
     * @param organizationMap
     * @param rootOrganizations
     * @return
     */
    public static String getDepOrgNameById(String id, Map<String, Organization> organizationMap, List<Organization> rootOrganizations) {
        Organization depOrgById = getCompanyById(id, organizationMap, rootOrganizations);
        if (depOrgById != null)
            return depOrgById.getName();
        return "";
    }

    /**
     * 根据id查找公司组织，未找到返回null
     */
    public static Organization getCompanyById(String id) {
        IOrganizationRepository repository = (IOrganizationRepository) ApplicationContextTool.getBean("organizationRepository");
        Organization organization = repository.selectById(id);
        if (organization == null)
            return new Organization();
        if (organization.getLevel() <= 2) {
            return organization;
        } else {
            return getCompanyById(organization.getpId());
        }
    }

    /**
     * 根据id查找公司组织，未找到返回null
     *
     * @param id
     * @param organizationMap
     * @return
     */
    public static Organization getCompanyById(String id, Map<String, Organization> organizationMap, List<Organization> rootOrganizations) {
        Organization organization = organizationMap.get(id);
        if (organization == null)
            return new Organization();
        if (rootOrganizations.contains(organization))
            return organization;

        Organization parent = organizationMap.get(organization.getpId());
        if (!rootOrganizations.contains(parent)) {
            organization = getCompanyById(organization.getpId(), organizationMap, rootOrganizations);
        }
        return organization;
    }

    /**
     * 根据id查找部门组织，未找到返回null
     *
     * @param id
     * @return
     */
    public static Organization getDepartmentById(String id) {
        if (StringUtils.isBlank(id))
            return new Organization();
        IOrganizationRepository repository = (IOrganizationRepository) ApplicationContextTool.getBean("organizationRepository");
        Organization organization = repository.selectById(id);
        if (organization == null)
            return new Organization();
        if (organization.getLevel() <= 3) {
            return organization;
        } else {
            return getDepartmentById(organization.getpId());
        }
    }

    /**
     * 根据id查找部门组织，未找到返回null
     *
     * @param id
     * @param organizationMap
     * @param rootOrganizations
     * @return
     */
    public static Organization getDepartmentById(String id, Map<String, Organization> organizationMap, List<Organization> rootOrganizations) {
        Organization organization = organizationMap.get(id);
        if (organization == null)
            return new Organization();
        if (judgeDepartmentLevel(organization, organizationMap, rootOrganizations))
            return organization;

        Organization parent = organizationMap.get(organization.getpId());
        if (!judgeDepartmentLevel(parent, organizationMap, rootOrganizations)) {
            organization = getDepartmentById(organization.getpId(), organizationMap, rootOrganizations);
        } else {
            organization = parent;
        }
        return organization;
    }

    /**
     * 判断是否为公司层级
     *
     * @param organization
     * @param rootOrganizations
     * @return
     */
    private static boolean judgeCompanyLevel(Organization organization, List<Organization> rootOrganizations) {
        boolean flag = false;
        for (Organization org : rootOrganizations) {
            if (org.getChildren() != null && org.getChildren().contains(organization))
                flag = true;
        }
        return flag;
    }

    /**
     * 判断是否为部门层级
     * (父组织为公司层级组织的即为部门)
     *
     * @param organization
     * @param rootOrganizations
     * @return
     */
    private static boolean judgeDepartmentLevel(Organization organization, Map<String, Organization> organizationMap, List<Organization> rootOrganizations) {
        if (organization == null)
            return false;
        Organization parentOrg = organizationMap.get(organization.getpId());
        if (parentOrg == null)
            return false;
        return judgeCompanyLevel(parentOrg, rootOrganizations);
    }

    /**
     * 是否为区县公司
     * @param organizationId
     * @return
     */
    public static boolean judgeCountyCompany(String organizationId){
        //三级组织 名称带分公司认为是区县公司
        Organization organization = getDepartmentById(organizationId);
        if (organization.getShortName().contains("分公司"))
            return true;
        return false;
    }

    /**
     * 获取组织所有子节点列表（包含自身）
     *
     * @param id
     * @param organizationMap
     * @return
     */
    public static List<Organization> getChildrenLoop(String id, Map<String, Organization> organizationMap) {
        List<Organization> resultList = new ArrayList<>();
        Organization organization = organizationMap.get(id);
        if (organization == null)
            return resultList;
        resultList.add(organization);
        if (CollectionUtils.isNotEmpty(organization.getChildren())) {
            for (Organization child : organization.getChildren()) {
                resultList.addAll(getChildrenLoop(child.getId(), organizationMap));
            }
        }
        return resultList;
    }

    /**
     * 获取组织所有子节点ID列表（包含自身）
     *
     * @param id
     * @return
     */
    public static List<String> getChildrenLoopId(String id) {
        Map<String, Organization> organizationMap = getOrganizationMap();
        List<Organization> organizationList = getChildrenLoop(id, organizationMap);
        return organizationList.stream().map(Organization::getId).collect(Collectors.toList());
    }

    /**
     * 根据id查找组织，未找到返回null
     */
    public static Organization getById(String id) {
        return getOrganizationMap().get(id);
    }

    /**
     * 根据id查找组织，未找到抛出异常
     */
    public static Organization getByIdReq(String id) throws ValidationException {
        Organization organization = getOrganizationMap().get(id);
        if (organization == null)
            throw new ValidationException("没有找到Id为“" + id + "”的组织。");

        return organization;
    }

    /**
     * 根据id集合查找组织，按参数顺序返回
     */
    public static List<Organization> getByIds(List<String> ids) {
        List<Organization> organizations = new ArrayList<>();
        if (ids == null || ids.size() == 0)
            return organizations;

        Map<String, Organization> organizationMap = getOrganizationMap();
        for (String id : ids) {
            Organization organization = organizationMap.get(id);
            if (organization != null)
                organizations.add(organization);
        }

        return organizations;
    }

    /**
     * 根据组织名称获取指定组织，从传入的orgId向上查找
     *
     * @param orgName
     * @param orgId
     * @return
     */
    public static Organization getUpTargetOrganizationByName(String orgName, String orgId) {
        if (StringUtils.isBlank(orgName))
            return null;
        Map<String, Organization> organizationMap = getOrganizationMap();
        Organization organization = organizationMap.get(orgId);
        if (organization == null)
            return null;
        if (StringTool.getString(organization.getShortName(), "-").contains(orgName)) {
            return organization;
        } else {
            return getUpTargetOrganizationByName(orgName, organization.getpId(), organizationMap);
        }
    }

    /**
     * 根据组织名称获取指定组织，从传入的orgId向上查找
     *
     * @param orgName
     * @param orgId
     * @param organizationMap
     * @return
     */
    public static Organization getUpTargetOrganizationByName(String orgName, String orgId, Map<String, Organization> organizationMap) {
        if (StringUtils.isBlank(orgName))
            return null;
        Organization organization = organizationMap.get(orgId);
        if (organization == null)
            return null;
        if (StringTool.getString(organization.getShortName(), "-").contains(orgName)) {
            return organization;
        } else {
            return getUpTargetOrganizationByName(orgName, organization.getpId(), organizationMap);
        }
    }

    /**
     * 根据组织名称获取指定组织，只查询分公司下一层
     *
     * @param orgName
     * @param companyId
     * @return
     */
    public static Organization getDepartmentByName(String orgName, String companyId) {
        if (StringUtils.isBlank(orgName))
            return null;
        Organization organization = getById(companyId);
        if (organization == null)
            return null;
        if (StringTool.getString(organization.getShortName(), "-").contains(orgName)) {
            return organization;
        }
        List<Organization> children = organization.getChildren();
        if (children == null || children.size() == 0) {
            return null;
        } else {
            for (Organization child : children) {
                if (StringTool.getString(child.getShortName(), "").contains(orgName)) {
                    return child;
                }
            }
            return null;
        }
    }

    /**
     * 获取当前分公司的工会部门
     * @return
     */
    public static Organization getCompanyUnionDepartment(String companyId){
        IOrganizationRepository repository = (IOrganizationRepository) ApplicationContextTool.getBean("organizationRepository");
        OrganizationCriteria organizationCriteria = new OrganizationCriteria();
        organizationCriteria.setParentIdList(Collections.singletonList(companyId));
        organizationCriteria.setShortNameContain("工会");
        List<Organization> organizations = repository.selectByCriteria(organizationCriteria);
        if (CollectionUtils.isNotEmpty(organizations)){
            return organizations.get(0);
        }
        return null;
    }

    /**
     * 获取当前分公司的人力资源部门（包括省本部的人力资源部门）
     *
     * @param companyId
     * @return
     */
    public static Organization getHumanResourceDepartmentByCompanyId(String companyId, String humanResourceName) {
        if (StringUtils.isBlank(humanResourceName)) {
            humanResourceName = "人力资源部";
        }
        IOrganizationRepository repository = (IOrganizationRepository) ApplicationContextTool.getBean("organizationRepository");
        Organization organization = repository.selectById(companyId);
        if (organization == null) {
            return null;
        }
        if (organization.getShortName().contains(humanResourceName)) {
            return organization;
        }
        OrganizationCriteria organizationCriteria = new OrganizationCriteria();
        organizationCriteria.setTreeParentId(companyId);
        List<Organization> children = repository.selectByCriteria(organizationCriteria);
        if (children == null || children.isEmpty()) {
            return null;
        } else {
            for (Organization child : children) {
                if (child.getShortName().contains(humanResourceName)) {
                    return child;
                }
            }
            return null;
        }
    }


    /**
     * 判断一个组织是否属于分公司
     *
     * @param orgId
     * @return
     */
    public static boolean judgeBranchCompany(String orgId) {
        Organization company = getCompanyById(orgId);
        return judgeBranchCompany(company);
    }

    /**
     * 判断一个组织是否属于分公司
     *
     * @param company
     * @return
     */
    public static boolean judgeBranchCompany(Organization company) {
        if (company == null)
            return false;
        return StringTool.getString(company.getShortName(), "-").contains("分公司");
    }

    /**
     * 判断一个组织是否属于省本部（不是分公司的默认省本部）
     *
     * @param orgId
     * @return
     */
    public static boolean judgeHeadquarters(String orgId) {
        return !judgeBranchCompany(orgId);
    }

    /**
     * 判断一个组织是否属于省本部
     *
     * @param organization
     * @return
     */
    public static boolean judgeHeadquarters(Organization organization) {
        return !judgeBranchCompany(organization);
    }

    /**
     * @param organizationList
     * @return
     */
    public static List<Map<String, Object>> changeToOrgTreeList(List<Organization> organizationList) {
        List<Map<String, Object>> resultList = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(organizationList)) {
            for (Organization organization : organizationList) {
                Map<String, Object> map = new HashMap<>();
                map.put("value", organization.getId());
                map.put("label", organization.getShortName());
                map.put("fullLabel", organization.getName());
                if (CollectionUtils.isNotEmpty(organization.getChildren())) {
                    List<Map<String, Object>> children = changeToOrgTreeList(organization.getChildren());
                    map.put("children", children);
                }
                resultList.add(map);
            }
        }
        return resultList;
    }

    /**
     * 获取部门列表
     *
     * @param companyId
     * @return
     */
    public static List<Organization> getDepartmentList(String companyId) {
        IOrganizationRepository repository = (IOrganizationRepository) ApplicationContextTool.getBean("organizationRepository");
        OrganizationCriteria criteria = new OrganizationCriteria();
        if (StringUtils.isNotBlank(companyId)) {
            criteria.setParentIdList(Collections.singletonList(companyId));
        }
        criteria.setLevel(3);
        criteria.setDisabledFlag(false);
        List<Organization> resultList = repository.selectByCriteria(criteria);
        resultList = organizationFilter(resultList);
        return resultList;
    }

    /**
     * 组织通用过滤
     * 【公司领导】组织过滤掉，不显示
     *
     * @param organizationList
     * @return
     */
    public static List<Organization> organizationFilter(List<Organization> organizationList) {
        if (CollectionUtils.isEmpty(organizationList))
            return new ArrayList<>();
        return organizationList.stream().filter(
                        organization -> !(StringUtils.isNotBlank(organization.getShortName()) && organization.getShortName().contains("公司领导")))
                .filter(organization -> !organization.isDisabled())
                .collect(Collectors.toList());
    }

}
