package nckd.jxccl.sit.hcsi.formplugin.web.tp;

import kd.bos.dataentity.entity.DynamicObjectCollection;
import kd.bos.dataentity.resource.ResManager;
import kd.bos.entity.tree.TreeNode;
import kd.bos.form.control.Search;
import kd.bos.form.control.TreeView;
import kd.bos.form.control.events.SearchEnterEvent;
import kd.bos.form.control.events.SearchEnterListener;
import kd.bos.form.plugin.AbstractFormPlugin;
import kd.bos.util.StringUtils;
import kd.hr.hbp.common.cache.HRPageCache;
import org.apache.commons.collections4.CollectionUtils;
import org.jetbrains.annotations.NotNull;

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

public class SitItemSelectTreePlugin extends AbstractFormPlugin implements SearchEnterListener {
    private static final String SEARCH_CONTROL = "nckd_treesearchap";
    private static final String TREE_VIEW = "nckd_treeviewap";
    private static final String ENTRY_SELECT = "nckd_itemselectentry";
    private static final String CACHE_ALL_ITEM_DATA = "allItemData";
    private static final String ITEM_TYPE_SL = "SL";
    private static final String ITEM_TYPE_SP = "SP";
    private static final String ITEM_TYPE_BS = "BS";
    private static final String PREFIX_SEPARATOR = "_@_";
    private static final String SALARY_ITEM_KEY = "salaryitemkey";
    private static final String SP_ITEM_KEY = "spitemkey";

    @Override
    public void registerListener(EventObject e) {
        super.registerListener(e);
        Search search = (Search)this.getView().getControl(SEARCH_CONTROL);
        search.addEnterListener(this);
    }

    @Override
    public void search(@NotNull SearchEnterEvent event) {
        String searchText = event.getText();
        boolean isExpend = StringUtils.isNotEmpty(searchText);

        HRPageCache pageCache = new HRPageCache(this.getView());
        Map<String, Map<String, Map<String, Object>>> dataMap =
                (Map)pageCache.get(CACHE_ALL_ITEM_DATA, Map.class);

        List<TreeNode> nodeItemList = loadSLItemChildNode(searchText, isExpend, dataMap);

        if (CollectionUtils.isEmpty(nodeItemList)) {
            showSearchCompleteNotification();
            return;
        }

        updateTreeView(nodeItemList);
    }

    private void showSearchCompleteNotification() {
        this.getView().showTipNotification(ResManager.loadKDString(
                "搜索已完成，未找到搜索项。",
                "CalResultTplItemTreePlugin_0",
                "swc-hsas-formplugin",
                new Object[0]
        ));
    }

    private void updateTreeView(List<TreeNode> nodeItemList) {
        TreeView treeView = (TreeView)this.getView().getControl(TREE_VIEW);
        treeView.deleteAllNodes();
        treeView.addNodes(nodeItemList);
        checkSelectedTreeNode(treeView, nodeItemList);
    }

    private void checkSelectedTreeNode(TreeView treeView, List<TreeNode> nodeList) {
        DynamicObjectCollection selectDatas = this.getView().getModel().getEntryEntity(ENTRY_SELECT);
        Set<String> uniqueCodeSet = selectDatas.stream()
                .map(selectData -> selectData.getString("itemunicodeid"))
                .collect(Collectors.toSet());

        List<TreeNode> checkNodeList = getCheckTreeNodeList(nodeList, uniqueCodeSet);
        if (CollectionUtils.isNotEmpty(checkNodeList)) {
            treeView.checkNodes(checkNodeList);
        }
    }

    public List<TreeNode> getCheckTreeNodeList(List<TreeNode> nodeList, Set<String> uniqueCodeSet) {
        if (CollectionUtils.isEmpty(uniqueCodeSet)) {
            return new ArrayList(0);
        } else {
            Queue<TreeNode> waitToCheckQueue = new LinkedList();
            waitToCheckQueue.addAll(nodeList);
            List<TreeNode> checkNodeList = new ArrayList(10);

            while(waitToCheckQueue.size() > 0) {
                TreeNode treeNode = (TreeNode)waitToCheckQueue.poll();
                List<TreeNode> childeList = treeNode.getChildren();
                if (CollectionUtils.isNotEmpty(childeList)) {
                    waitToCheckQueue.addAll(childeList);
                } else if (uniqueCodeSet.contains(treeNode.getId())) {
                    checkNodeList.add(treeNode);
                }
            }

            return checkNodeList;
        }
    }

    private List<TreeNode> loadSLItemChildNode(String name, boolean isExpend,
                                               Map<String, Map<String, Map<String, Object>>> dataMap) {
        List<Map<String, Object>> salaryItemList = getSalaryItemList(name, dataMap);
        if (CollectionUtils.isEmpty(salaryItemList)) {
            return Collections.emptyList();
        }

        Map<String, TreeNode> itemTypeNodeMap = new LinkedHashMap<>(salaryItemList.size());
        Map<String, List<TreeNode>> salaryItemNodeMap = new HashMap<>(16);

        salaryItemList.forEach(item -> {
            String itemTypeNum = (String)item.get("salaryitemtype_number");
            String itemTypeName = (String)item.get("salaryitemtype_name");

            // 创建子节点
            TreeNode childNode = new TreeNode(
                    itemTypeNum + PREFIX_SEPARATOR + ITEM_TYPE_SL,
                    String.valueOf(item.get("uniquecode")),
                    (String)item.get("name")
            );
            salaryItemNodeMap.computeIfAbsent(itemTypeNum, k -> new ArrayList<>(10)).add(childNode);

            // 创建类型节点
            itemTypeNodeMap.computeIfAbsent(itemTypeNum, k -> {
                TreeNode typeNode = new TreeNode(ITEM_TYPE_SL,
                        itemTypeNum + PREFIX_SEPARATOR + ITEM_TYPE_SL,
                        itemTypeName);
                typeNode.setExpend(isExpend);
                typeNode.setIsOpened(isExpend);
                return typeNode;
            });
        });

        return buildSalaryItemTree(itemTypeNodeMap, salaryItemNodeMap, isExpend);
    }

    private List<Map<String, Object>> getSalaryItemList(String name,
                                                        Map<String, Map<String, Map<String, Object>>> dataMap) {
        return StringUtils.isEmpty(name)
                ? mapToList(dataMap.get(SALARY_ITEM_KEY))
                : findItemByName(name, SALARY_ITEM_KEY, dataMap);
    }

    public static List<Map<String, Object>> mapToList(Map<String, Map<String, Object>> dataMap) {
        if (dataMap != null && dataMap.size() != 0) {
            List<Map<String, Object>> result = new ArrayList(dataMap.size());
            Iterator var2 = dataMap.entrySet().iterator();

            while(var2.hasNext()) {
                Map.Entry<String, Map<String, Object>> entry = (Map.Entry)var2.next();
                result.add(entry.getValue());
            }

            return result;
        } else {
            return new ArrayList();
        }
    }

    private List<TreeNode> buildSalaryItemTree(Map<String, TreeNode> itemTypeNodeMap,
                                               Map<String, List<TreeNode>> salaryItemNodeMap, boolean isExpend) {
        List<TreeNode> treeNodeList = itemTypeNodeMap.entrySet().stream()
                .map(entry -> {
                    TreeNode typeNode = entry.getValue();
                    typeNode.setChildren(salaryItemNodeMap.get(entry.getKey()));
                    return typeNode;
                })
                .collect(Collectors.toList());

        if (CollectionUtils.isEmpty(treeNodeList)) {
            return Collections.emptyList();
        }

        TreeNode itemRoot = new TreeNode("", ITEM_TYPE_SL,
                ResManager.loadKDString("薪酬项目-SL", "FormulaItemOrFuncTreeHelper_1",
                        "swc-hsas-business", new Object[0]));
        itemRoot.setChildren(treeNodeList);
        itemRoot.setExpend(isExpend);
        itemRoot.setIsOpened(isExpend);

        return Collections.singletonList(itemRoot);
    }

    private List<Map<String, Object>> findItemByName(String name, String itemName,
                                                     Map<String, Map<String, Map<String, Object>>> dataMap) {
        Map<String, Map<String, Object>> result = dataMap.get(itemName);
        if (result == null) {
            return Collections.emptyList();
        }

        return result.entrySet().stream()
                .filter(entry -> {
                    Map<String, Object> itemMap = entry.getValue();
                    if (itemMap == null && itemMap.size() == 0) {
                        return entry.getKey().contains(name);
                    }

                    String number = (String)itemMap.get("number");
                    return StringUtils.isNotEmpty(number) &&
                            (number.contains(name) || entry.getKey().contains(name));
                })
                .map(Map.Entry::getValue)
                .collect(Collectors.toList());
    }
}
