package cn.axzo.workflow.server.controller.delegate;

import cn.axzo.foundation.page.PageResp;
import cn.axzo.orggateway.api.nodeuser.OrgNodeUserApi;
import cn.axzo.orggateway.api.nodeuser.dto.OrgNodeUserDTO;
import cn.axzo.orggateway.api.nodeuser.req.ListOrgNodeUserReq;
import cn.axzo.workflow.common.enums.ApproverEmptyHandleTypeEnum;
import cn.axzo.workflow.common.exception.WorkflowEngineException;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
import cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.ListUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.flowable.bpmn.model.FlowElement;
import org.flowable.bpmn.model.UserTask;
import org.flowable.engine.delegate.DelegateExecution;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

import static cn.axzo.workflow.common.code.FlowableEngineRespCode.ENGINE_USER_TASK_CALC_ERROR;

/**
 * 转交给指定人
 */
@Slf4j
@Component
public class TransferToSpecifyTaskAssigneeSelector extends AbstractBpmnTaskAssigneeSelector {

    @Resource
    private OrgNodeUserApi orgNodeUserApi;

    @Override
    public String getType() {
        return ApproverEmptyHandleTypeEnum.specifyAssignee.getType();
    }

    @Override
    public List<BpmnTaskDelegateAssigner> select(FlowElement flowElement, DelegateExecution execution, Boolean throwException) {
        if (!(flowElement instanceof UserTask)) {
            return Collections.emptyList();
        }

        List<BpmnTaskDelegateAssigner> emptyAssignees =
                BpmnMetaParserHelper.getEmptyApproverSpecify((UserTask) flowElement)
                        .map(listStr -> JSON.parseArray(listStr, BpmnTaskDelegateAssigner.class))
                        .orElse(Collections.emptyList());
        if (CollectionUtils.isEmpty(emptyAssignees)) {
            return Collections.emptyList();
        }
        try {
            List<OrgNodeUserDTO> onlineUsers = new ArrayList<>();
            Set<Long> workspaceIds = emptyAssignees.stream()
                    .map(BpmnTaskDelegateAssigner::getTenantId)
                    .filter(NumberUtils::isDigits)
                    .map(Long::parseLong)
                    .collect(Collectors.toSet());

            List<Long> personIds = emptyAssignees.stream()
                    .map(BpmnTaskDelegateAssigner::getPersonId)
                    .filter(NumberUtils::isDigits)
                    .map(Long::parseLong)
                    .collect(Collectors.toList());
            ListOrgNodeUserReq searchReq = new ListOrgNodeUserReq();
            searchReq.setWorkspaceIds(workspaceIds);
            searchReq.setPersonIds(personIds);
            searchReq.setPage(1);
            searchReq.setPageSize(personIds.size());
            PageResp<OrgNodeUserDTO> pageResp = parseFoundationApiResult(() -> orgNodeUserApi.list(searchReq), "SpecifyAssigneeTaskAssigneeSelector#查询指定人员是否在职",
                    "cn.axzo.orggateway.api.nodeuser.OrgNodeUserApi.list", searchReq);
            if (pageResp != null) {
                onlineUsers = pageResp.getData();
            }
            // 只要有在职的人，不会走审批人为空
            if (ListUtils.emptyIfNull(onlineUsers).stream()
                    .filter(i -> Objects.equals(i.getIsDelete(), 0L))
                    .anyMatch(u -> emptyAssignees.stream()
                            .anyMatch(i -> Objects.equals(i.getPersonId(), String.valueOf(u.getPersonId()))
                                    && Objects.equals(i.getOuId(), String.valueOf(u.getOrganizationalUnitId()))))) {
                return emptyAssignees;
            }
            return Collections.emptyList();
        } catch (Exception e) {
            if (Boolean.TRUE.equals(throwException)) {
                throw new WorkflowEngineException(ENGINE_USER_TASK_CALC_ERROR, flowElement.getId(),
                        this.getType(), e.getMessage());
            } else {
                return Collections.emptyList();
            }
        }
    }
}
