package nckd.jxccl.swc.hsas.formplugin.web.outdata.basedata;

import kd.bos.dataentity.entity.DynamicObject;
import kd.bos.dataentity.entity.DynamicObjectCollection;
import kd.bos.dataentity.resource.ResManager;
import kd.bos.dataentity.serialization.SerializationUtils;
import kd.bos.dataentity.utils.ObjectUtils;
import kd.bos.dataentity.utils.StringUtils;
import kd.bos.entity.datamodel.AbstractFormDataModel;
import kd.bos.entity.datamodel.IDataModel;
import kd.bos.entity.datamodel.TableValueSetter;
import kd.bos.entity.tree.TreeNode;
import kd.bos.form.CloseCallBack;
import kd.bos.form.FormShowParameter;
import kd.bos.form.ShowType;
import kd.bos.form.control.Control;
import kd.bos.form.control.EntryGrid;
import kd.bos.form.control.TreeView;
import kd.bos.form.events.AfterDoOperationEventArgs;
import kd.bos.form.events.BeforeDoOperationEventArgs;
import kd.bos.form.events.ClosedCallBackEvent;
import kd.bos.form.operate.FormOperate;
import kd.bos.form.plugin.AbstractFormPlugin;
import kd.bos.util.CollectionUtils;
import kd.hr.hbp.common.cache.HRPageCache;
import kd.sdk.plugin.Plugin;
import nckd.jxccl.swc.hsas.formplugin.web.outdata.helper.OutItemSelectAddItemServiceHelper;

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

/**
 * Tyx 2025-12-08
 * 外单位数据导入项目选择页面 【nckd_outitemselect】
 */
public class OutItemSelectAddItemPlugin extends AbstractFormPlugin implements Plugin {

    private static final String BUTTON_CANCEL = "nckd_btncancel";
    private static final String BUTTON_SAVE = "nckd_btnsave";
    private static final String ENTRY_SELECT = "nckd_itemselectentry";
    private static final String TREE_VIEW = "nckd_treeviewap";
    private static final String FORM_MOVE_TO = "hsas_calitemmoveto";
    private static final String ITEM_TYPE_II = "SI";
    private static final String BASE_TYPE_II = "BI";
    private static final Map<String, String> ITEM_TYPE_MAPPING = new HashMap();
    private static final Map<String, String> ITEM_CATEGORY_MAPPING =  new HashMap();
    static {
        ITEM_TYPE_MAPPING.put("1", ITEM_TYPE_II);
        ITEM_TYPE_MAPPING.put("2", BASE_TYPE_II);
        ITEM_CATEGORY_MAPPING.put(ITEM_TYPE_II, ITEM_TYPE_II);
        ITEM_CATEGORY_MAPPING.put(BASE_TYPE_II, BASE_TYPE_II);
    }


    @Override
    public void registerListener(EventObject e) {
        super.registerListener(e);
        this.addClickListeners(BUTTON_CANCEL, BUTTON_SAVE);
    }

    @Override
    public void beforeBindData(EventObject e) {
        super.beforeBindData(e);
        long orgId = getOrgId();
        loadMainPageData();
        OutItemSelectAddItemServiceHelper helper = new OutItemSelectAddItemServiceHelper();
        Map<String, Map<String, Map<String, Object>>> dataMap = helper.getAllItemData(orgId);
        initItemTree(dataMap);
    }

    private void initItemTree(Map<String, Map<String, Map<String, Object>>> dataMap) {
        TreeView treeView = (TreeView)this.getView().getControl(TREE_VIEW);
        List<TreeNode> nodeList = buildTreeNodeList(dataMap);

        treeView.deleteAllNodes();
        treeView.addNodes(nodeList);

        updatePageCache(nodeList, dataMap);
        checkSelectedTreeNode(treeView, nodeList);
    }

    private List<TreeNode> buildTreeNodeList(Map<String, Map<String, Map<String, Object>>> dataMap) {
        List<TreeNode> list = new ArrayList<>();
        list.addAll(OutItemSelectAddItemServiceHelper.loadSalaryItemChildNode(null, false, dataMap));
        list.addAll(OutItemSelectAddItemServiceHelper.loadBaseItemChildNode(null, false, dataMap));
        return list;
    }

    private void updatePageCache(List<TreeNode> nodeList, Map<String, Map<String, Map<String, Object>>> dataMap) {
        HRPageCache pageCache = new HRPageCache(this.getView());
        Map<String, TreeNode> treeNodeMap = nodeList.stream()
                .collect(Collectors.toMap(TreeNode::getId, Function.identity()));

        pageCache.put("tree", SerializationUtils.serializeToBase64(treeNodeMap));
        pageCache.put("allItemData", dataMap);
        pageCache.put("simpleAllItemData", rebuildData(dataMap));
    }

    private Map<String, Map<String, String>> rebuildData(Map<String, Map<String, Map<String, Object>>> dataMap) {
        if (dataMap != null && dataMap.size() != 0) {
            return Collections.emptyMap();
        }

        return dataMap.entrySet().stream()
                .collect(Collectors.toMap(
                        Map.Entry::getKey,
                        entry -> entry.getValue().entrySet().stream()
                                .collect(Collectors.toMap(
                                        Map.Entry::getKey,
                                        innerEntry -> (String)innerEntry.getValue().get("uniquecode")
                                ))
                ));
    }

    public void addColumn() {
        TreeView treeView = (TreeView)this.getView().getControl(TREE_VIEW);
        List<String> selectNodeIds = treeView.getTreeState().getCheckedNodeIds();
        if (CollectionUtils.isEmpty(selectNodeIds)) {
            this.getView().showTipNotification(ResManager.loadKDString("请先选中数据。", "CalResultTplAddItemPlugin_0", "swc-hsas-formplugin", new Object[0]));
            return;
        }

        HRPageCache pageCache = new HRPageCache(this.getView());
        Map<String, TreeNode> nodeMap = getNodeMapFromCache(pageCache);
        Map<String, Map<String, Map<String, Object>>> dataMap = (Map)pageCache.get("allItemData", Map.class);

        AbstractFormDataModel model = (AbstractFormDataModel)this.getModel();
        model.beginInit();

        try {
            TableValueSetter vs = createTableValueSetter();
            List<TreeNode> checkNodeList = new ArrayList<>(selectNodeIds.size());

            for (String selectNodeId : selectNodeIds) {
                TreeNode treeNode = getTreeNodeByTreeId(nodeMap, selectNodeId);
//                TreeNode treeNode = nodeMap.get(selectNodeId);
                if (!isValidNode(treeNode, selectNodeId)) {
                    continue;
                }

                String itemCategory = getItemCategory(treeNode);
                String itemNum = getItemNumber(dataMap, itemCategory, treeNode.getText(), treeNode);
                String itemUnicodeId = getItemUnicodeId(treeNode.getId(), treeNode.getText());

                vs.addRow(new Object[]{itemCategory, itemNum, treeNode.getText(), itemUnicodeId, treeNode.getId()});
                checkNodeList.add(treeNode);
            }

            model.batchCreateNewEntryRow(ENTRY_SELECT, vs);
            this.getView().updateView(ENTRY_SELECT);

            if (CollectionUtils.isNotEmpty(checkNodeList)) {
                treeView.checkNodes(checkNodeList);
            }
        } finally {
            model.endInit();
        }
    }

    private Map<String, TreeNode> getNodeMapFromCache(HRPageCache pageCache) {
        String cacheTreeNodeStr = (String)pageCache.get("tree", String.class);
        return (Map)SerializationUtils.deSerializeFromBase64(cacheTreeNodeStr);
    }

    private TableValueSetter createTableValueSetter() {
        TableValueSetter vs = new TableValueSetter(new String[0]);
        vs.addField("nckd_itemcategory", new Object[0]);
        vs.addField("nckd_itemnumber", new Object[0]);
        vs.addField("nckd_itemname", new Object[0]);
        vs.addField("nckd_itemunicodeid", new Object[0]);
        vs.addField("nckd_treenodeid", new Object[0]);
        return vs;
    }

    private boolean isValidNode(TreeNode treeNode, String selectNodeId) {
        if (treeNode == null || StringUtils.isEmpty(treeNode.getId())) {
            return false;
        }

        String treeNodeId = treeNode.getId();

        if(treeNode.getChildren() != null) {
            return false;
        }

//        if (treeNodeId.equals("II") || treeNodeId.equals("BI")) {
//            return false;
//        }

        return !isExistTreeNode(selectNodeId);
    }

    private String getItemCategory(TreeNode treeNode) {
        //String treeNodeId = treeNode.getId();
        String itemCategory = treeNode.getParentid().substring(0, 2);
        return normalizeItemCategory(itemCategory);
////        String itemCategory = ITEM_TYPE_II;
//        if(treeNode.getId().equals("999990") || treeNode.getId().equals("999991")){
//            return normalizeItemCategory(BASE_TYPE_II);
//        }
//        else {
//            return normalizeItemCategory(ITEM_TYPE_II);
//        }
    }

    private void removeCheckNode(int[] rows) {
        DynamicObjectCollection selectDatas = this.getView().getModel().getEntryEntity(ENTRY_SELECT);
        HRPageCache pageCache = new HRPageCache(this.getView());
        Map<String, TreeNode> nodeMap = getNodeMapFromCache(pageCache);

        List<String> removeCheckNodeList = Arrays.stream(rows)
                .mapToObj(index -> {
                    DynamicObject selectData = (DynamicObject)selectDatas.get(index);
                    return nodeMap.get(selectData.getString("nckd_itemunicodeid"));
                })
                .filter(Objects::nonNull)
                .map(TreeNode::getId)
                .collect(Collectors.toList());

        TreeView treeView = (TreeView)this.getView().getControl(TREE_VIEW);
        treeView.uncheckNodes(removeCheckNodeList);
    }

    private String getItemNumber(Map<String, Map<String, Map<String, Object>>> dataMap, String itemCategory, String treeNodeName, TreeNode treeNode) {
        String mapKey = getItemMapKey(itemCategory, treeNode);
        Map<String, Map<String, Object>> itemMap = (Map)dataMap.get(mapKey);

        if (itemMap == null) {
            return "";
        }

        Map<String, Object> nameMap = itemMap.get(treeNodeName);
        if (nameMap != null && nameMap.size() != 0) {
            String number = (String)nameMap.get("number");
            return StringUtils.isEmpty(number) ? "" : number;
        }
        else {
            return "";
        }
    }

    private String getItemMapKey(String itemCategory, TreeNode treeNode) {
        switch (itemCategory) {
            case ITEM_TYPE_II:
                return "salaryitemkey";
            case BASE_TYPE_II:
                return "baseitemkey";
            default:
                return "";
        }
    }

    public boolean isExistTreeNode(String selectTreeNodeId) {
        DynamicObjectCollection itemDatas = this.getModel().getEntryEntity(ENTRY_SELECT);
        return itemDatas.stream()
                .anyMatch(itemData -> StringUtils.equals(
                        itemData.getString("nckd_treenodeid"),
                        selectTreeNodeId
                ));
    }

    private long getOrgId() {
        return ((DynamicObject)this.getView().getParentView().getModel().getValue("org")).getLong("id");
    }

    @Override
    public void beforeDoOperation(BeforeDoOperationEventArgs args) {
        super.beforeDoOperation(args);
        FormOperate formOperate = (FormOperate)args.getSource();
        if ("do_moveto".equals(formOperate.getOperateKey())) {
            openMoveToPage(args);
        }
    }

    @Override
    public void afterDoOperation(AfterDoOperationEventArgs args) {
        super.afterDoOperation(args);
        switch (args.getOperateKey()) {
            case "do_addcolumn":
                addColumn();
                break;
            case "do_removecolumn":
                removeColumn();
        }
    }

    @Override
    public void click(EventObject evt) {
        super.click(evt);
        Control source = (Control)evt.getSource();
        switch (source.getKey()) {
            case BUTTON_CANCEL:
                this.getView().close();
                break;
            case BUTTON_SAVE:
                btnOkClickEvent();
        }
    }

    @Override
    public void closedCallBack(ClosedCallBackEvent evt) {
        if ("movetoclosed".equals(evt.getActionId())) {
            moveToClosedEvent(evt);
        }
    }

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

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

    public List<TreeNode> getCheckTreeNodeList(List<TreeNode> nodeList, Set<String> uniqueCodeSet) {
        if (org.apache.commons.collections4.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 (org.apache.commons.collections4.CollectionUtils.isNotEmpty(childeList)) {
                    waitToCheckQueue.addAll(childeList);
                } else if (uniqueCodeSet.contains(treeNode.getId())) {
                    checkNodeList.add(treeNode);
                }
            }

            return checkNodeList;
        }
    }

    public void loadMainPageData() {
        loadMainPageDataFromOutImpTempate();
    }

    private void loadMainPageDataFromOutImpTempate() {
        DynamicObjectCollection matchRelationDatas = this.getView().getParentView().getModel()
                .getEntryEntity("nckd_outimptplentry");
        if (CollectionUtils.isEmpty(matchRelationDatas)) {
            return;
        }

        IDataModel model = this.getModel();
        for (DynamicObject matchRelationData : matchRelationDatas) {
            if(matchRelationData.getBoolean("nckd_ispreset")) {
                continue;
            }
            String itemType = matchRelationData.getString("nckd_itemtype");
            String itemCategory = ITEM_TYPE_MAPPING.get(itemType);

            if (itemCategory != null) {
                int detailIndex = model.createNewEntryRow(ENTRY_SELECT);
                populateEntryData(model, matchRelationData, itemCategory, detailIndex);
            }
        }
        this.getView().updateView(ENTRY_SELECT);
    }

    private void populateEntryData(IDataModel model, DynamicObject sourceData, String itemCategory, int detailIndex) {
        model.setValue("nckd_itemnumber", sourceData.getString("nckd_itemnumber"), detailIndex);
        model.setValue("nckd_itemcategory", itemCategory, detailIndex);
        model.setValue("nckd_itemname", sourceData.getString("nckd_itemname"), detailIndex);
        model.setValue("nckd_itemunicodeid", sourceData.getString("nckd_uniquecode"), detailIndex);
        model.setValue("nckd_treenodeid", sourceData.getString("nckd_itemid"), detailIndex);
    }

    public void btnOkClickEvent() {
        DynamicObjectCollection entryDatas = this.getModel().getEntryEntity(ENTRY_SELECT);
        if (CollectionUtils.isEmpty(entryDatas)) {
            this.getView().showTipNotification(ResManager.loadKDString("请先添加项目。", "CalResultTplAddItemPlugin_4", "swc-hsas-formplugin", new Object[0]));
            return;
        }
        this.getView().returnDataToParent(entryDatas);
        this.getView().close();
    }

    public void moveToClosedEvent(ClosedCallBackEvent evt) {
        Map<String, Object> returnData = (Map)evt.getReturnData();
        if (ObjectUtils.isEmpty(returnData) || !"ok".equals(returnData.get("clickStatus"))) {
            return;
        }

        EntryGrid entryGrid = (EntryGrid)this.getView().getControl(ENTRY_SELECT);
        int[] rows = entryGrid.getSelectRows();
        int oldRow = rows[0];
        int newRow = (Integer)returnData.get("rownumber") - 1;

        IDataModel model = this.getModel();
        DynamicObjectCollection datas = model.getEntryEntity(ENTRY_SELECT);
        newRow = Math.min(newRow, datas.size() - 1);

        if (oldRow != newRow) {
            DynamicObject oldObj = (DynamicObject)datas.get(oldRow);
            model.deleteEntryRow(ENTRY_SELECT, oldRow);
            model.createNewEntryRow(ENTRY_SELECT, newRow, oldObj);
            entryGrid.selectRows(newRow, true);
        }
    }

    private String normalizeItemCategory(String itemCategory) {
        return ITEM_CATEGORY_MAPPING.getOrDefault(itemCategory, itemCategory);
    }

    public String getItemUnicodeId(String treeNodeId, String treeNodeName) {
        HRPageCache pageCache = new HRPageCache(this.getView());
        Map<String, Map<String, String>> dataMap = (Map)pageCache.get("simpleAllItemData", Map.class);
        if (ObjectUtils.isEmpty(dataMap)) {
            return "";
        }

        return dataMap.values().stream()
                .map(itemData -> itemData.get(treeNodeName))
                .filter(uniqueCode -> StringUtils.equals(uniqueCode, treeNodeId))
                .findFirst()
                .orElse("");
    }

    public TreeNode getTreeNodeByTreeId(Map<String, TreeNode> nodeMap, String treeId) {
        if (nodeMap == null || StringUtils.isEmpty(treeId)) {
            return null;
        }

        for (Map.Entry<String, TreeNode> entry : nodeMap.entrySet()) {
            TreeNode node = entry.getValue();
            TreeNode result = getSubTreeNode(treeId, node);
            if (result != null) {
                return result;
            }
        }
        return null;
    }

    private TreeNode getSubTreeNode(String treeId, TreeNode node) {
        if (node == null) {
            return null;
        }
        // 检查当前节点
        if (treeId.equals(node.getId())) {
            return node;
        }
        // 递归检查子节点
        if (node.getChildren() != null) {
            for (TreeNode child : node.getChildren()) {
                TreeNode result = getSubTreeNode(treeId, child);
                if (result != null) {
                    return result;
                }
            }
        }
        return null;
    }

    public void removeColumn() {
        EntryGrid entryGrid = (EntryGrid)this.getView().getControl(ENTRY_SELECT);
        int[] rows = entryGrid.getSelectRows();

        if (rows == null || rows.length == 0) {
            this.getView().showTipNotification(ResManager.loadKDString("请选中一行再进行操作。", "CalResultTplAddItemPlugin_1", "swc-hsas-formplugin", new Object[0]));
            return;
        }

        removeCheckNode(rows);
        this.getModel().deleteEntryRows(ENTRY_SELECT, rows);
    }

    public void openMoveToPage(BeforeDoOperationEventArgs args) {
        EntryGrid entryGrid = (EntryGrid)this.getView().getControl(ENTRY_SELECT);
        int[] rows = entryGrid.getSelectRows();

        if (rows == null || rows.length == 0) {
            this.getView().showTipNotification(ResManager.loadKDString("请选择要执行的数据。", "CalResultTplAddItemPlugin_2", "swc-hsas-formplugin", new Object[0]));
            args.setCancel(true);
            return;
        }

        if (rows.length != 1) {
            this.getView().showTipNotification(ResManager.loadKDString("只能选择一条记录。", "CalResultTplAddItemPlugin_3", "swc-hsas-formplugin", new Object[0]));
            args.setCancel(true);
            return;
        }

        FormShowParameter showParameter = new FormShowParameter();
        showParameter.setFormId(FORM_MOVE_TO);
        showParameter.getOpenStyle().setShowType(ShowType.Modal);
        showParameter.setParentPageId(this.getView().getPageId());
        showParameter.setCaption(ResManager.loadKDString("移动到", "CalResultTplAddItemPlugin_5", "swc-hsas-formplugin", new Object[0]));
        showParameter.setCloseCallBack(new CloseCallBack(this, "movetoclosed"));
        this.getView().showForm(showParameter);
    }

}