package cn.axzo.workflow.server.controller.listener.task.service.impl;

import cn.axzo.framework.jackson.utility.JSON;
import cn.axzo.workflow.common.enums.BpmnButtonEnum;
import cn.axzo.workflow.common.enums.BpmnFlowNodeType;
import cn.axzo.workflow.common.model.request.bpmn.BpmnButtonConf;
import cn.axzo.workflow.common.model.request.bpmn.BpmnButtonMetaInfo;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
import cn.axzo.workflow.common.model.request.bpmn.task.ExtHiTaskSearchDTO;
import cn.axzo.workflow.core.common.context.TaskOperationContext;
import cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper;
import cn.axzo.workflow.core.repository.entity.ExtAxHiTaskInst;
import cn.axzo.workflow.core.service.ExtAxHiTaskInstService;
import cn.axzo.workflow.server.controller.listener.task.service.CheckApproverService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
import org.flowable.bpmn.model.FlowElement;
import org.flowable.bpmn.model.Process;
import org.flowable.bpmn.model.UserTask;
import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.flowable.engine.impl.persistence.entity.ActivityInstanceEntity;
import org.flowable.engine.impl.util.CommandContextUtil;
import org.flowable.task.service.delegate.DelegateTask;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_INITIATOR;
import static cn.axzo.workflow.common.constant.BpmnConstants.NO_ASSIGNEE;
import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_BUSINESS;
import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_EMPTY;
import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_STARTER;
import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_TASK;
import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.APPROVED;

/**
 * REQ-2596. 自动过审规则：
 * a. 审批人=发起人/历史审批人
 * b. 连续节点
 * c. 当前节点有同意按钮
 */
@Slf4j
@Component
@AllArgsConstructor
public class CheckApproverServiceImpl implements CheckApproverService {

    private final ExtAxHiTaskInstService extAxHiTaskInstService;

    public boolean checkApproverExists(DelegateTask delegateTask, UserTask userTask, Process mainProcess, TaskOperationContext taskOperationContext) {
        AtomicBoolean exists = new AtomicBoolean(false);
        FlowElement currentFlowElement = mainProcess.getFlowElement(delegateTask.getTaskDefinitionKey());
        BpmnFlowNodeType currentNodeType = BpmnMetaParserHelper.getNodeType(currentFlowElement).orElse(NODE_EMPTY);
        //业务节点,指定业务审批人,或者业务设置了审批人,也要参与自动过审,node_type为NODE_BUSINESS,节点元素类型为UserTask
        //业务节点审批人为空,或者人员未指定,此时不进行自动过审操作,需要再业务指定审批人后,再做自动过审动作
        if (!(Objects.equals(currentNodeType, NODE_TASK) || Objects.equals(currentNodeType, NODE_BUSINESS)) ||
                !StringUtils.hasText(delegateTask.getAssignee()) ||
                delegateTask.getAssignee().equals(NO_ASSIGNEE)) {
            log.info("CheckApproverServiceImpl#checkApproverExists...节点类型:{},审批人:{}", currentNodeType, delegateTask.getAssignee());
            return exists.get();
        }
        Optional<BpmnButtonConf> optConfig = BpmnMetaParserHelper.getButtonConfig(mainProcess, delegateTask.getTaskDefinitionKey());
        if (!optConfig.isPresent()) {
            log.info("CheckApproverServiceImpl#checkApproverExists...节点未配置按钮,节点ID:{}", delegateTask.getTaskDefinitionKey());
            return exists.get();
        }
        BpmnButtonConf bpmnButtonConf = optConfig.get();
        List<BpmnButtonMetaInfo> currentButtons = bpmnButtonConf.getCurrent();
        if (CollectionUtils.isEmpty(currentButtons)) {
            log.info("CheckApproverServiceImpl#checkApproverExists...节点按钮配置为空,节点ID:{}", delegateTask.getTaskDefinitionKey());
            return exists.get();
        }
        Optional<BpmnButtonMetaInfo> agreeButton = currentButtons.stream()
                .filter(button -> button.getType().equals("SYSTEM")  //系统按钮
                        && button.getChecked() != null && button.getChecked() //选中
                        && (button.getDisabled() == null || !button.getDisabled()) //没用禁用
                        && button.getBtnKey().equals(BpmnButtonEnum.BPMN_APPROVE.getBtnKey())) //类型为同意
                .findFirst();
        //不存在同意按钮
        if (!agreeButton.isPresent()) {
            log.info("CheckApproverServiceImpl#checkApproverExists...节点未配置同意按钮,节点ID:{}", delegateTask.getTaskDefinitionKey());
            return exists.get();
        }
        ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration();
        List<ActivityInstanceEntity> actInsts = processEngineConfiguration.getActivityInstanceEntityManager()
                .findActivityInstancesByProcessInstanceId(delegateTask.getProcessInstanceId(), false);

        actInsts.stream().map(i -> new StringBuilder()
                        .append(i.getActivityId()).append(":")
                        .append(i.getActivityType()).append(":")
                        .append(i.getEndTime()))
                .collect(Collectors.toList())
                .forEach(i -> log.info("checkApproveServiceImpl inst: {}", i.toString()));

        actInsts
                .stream()
                .filter(i -> !Objects.equals(i.getActivityId(), userTask.getId()))
                .filter(i -> !Objects.equals(i.getActivityType(), "exclusiveGateway"))
                .filter(i -> !Objects.equals(i.getActivityType(), "sequenceFlow"))
                .filter(i -> !Objects.equals(i.getActivityType(), "startEvent"))
                .filter(i -> Objects.nonNull(i.getEndTime()))
                .max(Comparator.comparing(ActivityInstanceEntity::getEndTime))
                .ifPresent(i -> {
                    log.info("CheckApproverServiceImpl#checkApproverExists...上一个节点ID:{},类型:{}", i.getActivityId(), i.getActivityType());
                    // 与发起人比对
                    if (Objects.equals(NODE_STARTER.getType(), i.getActivityId())) {
                        log.info("CheckApproverServiceImpl#checkApproverExists...与发起人比对");
                        BpmnTaskDelegateAssigner initiator = BpmnTaskDelegateAssigner.toObjectCompatible(delegateTask.getVariable(INTERNAL_INITIATOR));
                        if (Objects.nonNull(initiator) && initiator.comparePersonIdToOther(delegateTask.getAssignee())) {
                            exists.compareAndSet(false, true);
                        }
                    } else {
                        log.info("CheckApproverServiceImpl#checkApproverExists...与历史审批人比对, 上节点ID：{}", i.getActivityId());
                        FlowElement flowElement = mainProcess.getFlowElement(i.getActivityId());
                        BpmnMetaParserHelper.getNodeType(flowElement).ifPresent(j -> {
                            log.info("CheckApproverServiceImpl#checkApproverExists...上一个节点类型:{}", j);
                            //上一节点如果是业务节点,但是是人员审批,也需要加入到自动过审
                            if (Objects.equals(NODE_TASK, j) || (Objects.equals(NODE_BUSINESS, j) && flowElement.getClass().isAssignableFrom(UserTask.class))) {
                                ExtHiTaskSearchDTO searchDTO = new ExtHiTaskSearchDTO();
                                searchDTO.setProcessInstanceId(delegateTask.getProcessInstanceId());
                                List<ExtAxHiTaskInst> extAxHiTaskInsts = extAxHiTaskInstService.queryList(searchDTO);
                                extAxHiTaskInsts.sort(Comparator.comparing(ExtAxHiTaskInst::getCreateAt));
                                log.info("CheckApproverServiceImpl#checkApproverExists...历史审批任务列表:{}", JSON.toJSONString(extAxHiTaskInsts));
                                List<ExtAxHiTaskInst> previousTasks = new ArrayList<>();
                                for (int k = extAxHiTaskInsts.size() - 1; k > 0; k--) {
                                    ExtAxHiTaskInst extAxHiTaskInst = extAxHiTaskInsts.get(k);
                                    if (!extAxHiTaskInst.getTaskDefinitionKey().equals(i.getActivityId()) && !CollectionUtils.isEmpty(previousTasks)) {
                                        break;
                                    }
                                    if (extAxHiTaskInst.getTaskDefinitionKey().equals(i.getActivityId())) {
                                        previousTasks.add(extAxHiTaskInst);
                                    }
                                }
                                log.info("CheckApproverServiceImpl#checkApproverExists...待比对的历史审批任务列表:{}", JSON.toJSONString(previousTasks));
                                previousTasks.stream()
                                        .filter(e -> Objects.equals(e.getStatus(), APPROVED.getStatus()))
                                        .map(ExtAxHiTaskInst::getAssignee)
                                        .filter(Objects::nonNull)
                                        .filter(StringUtils::hasText)
                                        .filter(k -> specialApproverComparison(k, delegateTask.getAssignee()))
                                        .findAny().ifPresent(k -> exists.compareAndSet(false, true));
                            }
                        });
                    }
                });
        return exists.get();
    }

    /**
     * 特殊审批人字段的比对, 兼容旧迭代导致的数据格式
     *
     * @return
     */
    private boolean specialApproverComparison(String compareAssignee, String currentAssignee) {
        if (StringUtils.hasText(compareAssignee) && StringUtils.hasText(currentAssignee)) {
            String[] compareSplit = compareAssignee.split("\\|");
            String[] currentSplit = currentAssignee.split("\\|");
            if (compareSplit.length == 2 || currentSplit.length == 2) {
                return Objects.equals(compareSplit[1], currentSplit[1]);
            }
        }
        return false;
    }

    @Override
    public DefaultArtifactVersion getVersion() {
//        return new DefaultArtifactVersion(FLOW_SERVER_VERSION_130);
        return null;
    }
}
