package cn.cordys.crm.dashboard.service;

import cn.cordys.common.dto.NodeSortCountResultDTO;
import cn.cordys.common.dto.NodeSortQueryParam;
import cn.cordys.common.exception.GenericException;
import cn.cordys.common.util.NodeSortUtils;
import cn.cordys.common.util.Translator;
import cn.cordys.crm.dashboard.dto.DropNode;
import cn.cordys.crm.dashboard.dto.MoveNodeSortDTO;
import cn.cordys.crm.system.dto.request.NodeMoveRequest;
import org.apache.commons.lang3.Strings;

import java.util.function.Function;

public abstract class DashboardSortService {

    private static final String MOVE_POS_OPERATOR_LESS = "lessThan";
    private static final String MOVE_POS_OPERATOR_MORE = "moreThan";
    private static final String DRAG_NODE_NOT_EXIST = "drag_node.not.exist";

    public abstract void updatePos(String id, long pos);

    public abstract void refreshPos(String testPlanId);

    /**
     * 构建节点移动的请求参数
     *
     * @param isDesc 是否是降序排列
     */
    public NodeMoveRequest getNodeMoveRequest(String moveId, String targetId, String moveMode, boolean isDesc) {
        NodeMoveRequest request = new NodeMoveRequest();
        request.setDragNodeId(moveId);
        request.setDropNodeId(targetId);
        request.setAndConvertDropPosition(moveMode, isDesc);
        return request;
    }


    /**
     * 构建节点排序的参数
     *
     * @param sortRangeId       排序范围ID
     * @param request           拖拽的前端请求参数
     * @param selectIdNodeFunc  通过id查询节点的函数
     * @param selectPosNodeFunc 通过parentId和pos运算符查询节点的函数
     */
    public MoveNodeSortDTO getNodeSortDTO(String sortRangeId, NodeMoveRequest request, Function<String, DropNode> selectIdNodeFunc, Function<NodeSortQueryParam, DropNode> selectPosNodeFunc) {
        if (Strings.CS.equals(request.getDragNodeId(), request.getDropNodeId())) {
            //两种节点不能一样
            throw new GenericException(Translator.get("invalid_parameter") + ": drag node  and drop node");
        }

        DropNode dragNode = selectIdNodeFunc.apply(request.getDragNodeId());
        if (dragNode == null) {
            throw new GenericException(Translator.get(DRAG_NODE_NOT_EXIST) + ":" + request.getDragNodeId());
        }

        DropNode dropNode = selectIdNodeFunc.apply(request.getDropNodeId());
        if (dropNode == null) {
            throw new GenericException(Translator.get(DRAG_NODE_NOT_EXIST) + ":" + request.getDropNodeId());
        }

        DropNode previousNode;
        DropNode nextNode;

        if (request.getDropPosition() == 1) {
            //dropPosition=1: 放到dropNode节点后，原dropNode后面的节点之前
            previousNode = dropNode;
            NodeSortQueryParam sortParam = new NodeSortQueryParam();
            sortParam.setPos(previousNode.getPos());
            sortParam.setOperator(MOVE_POS_OPERATOR_MORE);
            sortParam.setParentId(sortRangeId);
            nextNode = selectPosNodeFunc.apply(sortParam);
        } else if (request.getDropPosition() == -1) {
            //dropPosition=-1: 放到dropNode节点前，原dropNode前面的节点之后
            nextNode = dropNode;
            NodeSortQueryParam sortParam = new NodeSortQueryParam();
            sortParam.setPos(nextNode.getPos());
            sortParam.setOperator(MOVE_POS_OPERATOR_LESS);
            sortParam.setParentId(sortRangeId);
            previousNode = selectPosNodeFunc.apply(sortParam);
        } else {
            throw new GenericException(Translator.get("invalid_parameter") + ": dropPosition");
        }

        return new MoveNodeSortDTO(sortRangeId, dragNode, previousNode, nextNode);
    }


    //排序
    public void sort(MoveNodeSortDTO sortDTO) {
        // 获取相邻节点
        DropNode previousNode = sortDTO.getPreviousNode();
        DropNode nextNode = sortDTO.getNextNode();
        NodeSortCountResultDTO countResultDTO = NodeSortUtils.countModuleSort(
                previousNode == null ? -1 : previousNode.getPos(),
                nextNode == null ? -1 : nextNode.getPos());
        updatePos(sortDTO.getSortNode().getId(), countResultDTO.getPos());
        if (countResultDTO.isRefreshPos()) {
            refreshPos(sortDTO.getSortRangeId());
        }
    }
}
