package cn.stylefeng.workflow.instance.modular.business.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.stylefeng.roses.kernel.auth.api.context.LoginContext;
import cn.stylefeng.workflow.api.WorkflowApi;
import cn.stylefeng.workflow.api.entity.instance.RuntimeInstance;
import cn.stylefeng.workflow.api.entity.task.RuTask;
import cn.stylefeng.workflow.api.enums.TaskStatusEnum;
import cn.stylefeng.workflow.api.enums.WorkflowStartTypeEnum;
import cn.stylefeng.workflow.api.exception.WorkflowException;
import cn.stylefeng.workflow.api.pojo.workflowapi.FlowApiStartRequest;
import cn.stylefeng.workflow.api.pojo.workflowapi.FlowDefinitionStartRequest;
import cn.stylefeng.workflow.design.api.ModelApi;
import cn.stylefeng.workflow.instance.api.WorkflowControlApi;
import cn.stylefeng.workflow.instance.api.pojo.request.WorkflowStartRequest;
import cn.stylefeng.workflow.instance.modular.business.enums.BusinessLinkExceptionEnum;
import cn.stylefeng.workflow.instance.modular.business.service.BusinessLinkService;
import cn.stylefeng.workflow.instance.modular.task.service.RuTaskService;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Service
public class WorkflowApiServiceImpl implements WorkflowApi {

    @Resource
    private WorkflowControlApi workflowControlApi;

    @Resource
    private BusinessLinkService businessLinkService;

    @Resource
    private ModelApi modelApi;

    @Resource
    private RuTaskService ruTaskService;

    @Override
    public RuntimeInstance start(FlowApiStartRequest flowApiStartRequest) {

        if (flowApiStartRequest == null) {
            throw new WorkflowException(BusinessLinkExceptionEnum.PARAM_EMPTY, "整体");
        }

        if (ObjectUtil.isEmpty(flowApiStartRequest.getWorkflowStartType())) {
            throw new WorkflowException(BusinessLinkExceptionEnum.PARAM_EMPTY, "流程发起方式");
        }

        if (ObjectUtil.isEmpty(flowApiStartRequest.getBusinessCode())) {
            throw new WorkflowException(BusinessLinkExceptionEnum.PARAM_EMPTY, "业务编码");
        }

        Long flowModelId = businessLinkService.getModelIdByBusinessCode(flowApiStartRequest.getBusinessCode());

        Long flowDefinitionId = modelApi.getModelLatestDefinitionId(flowModelId);

        WorkflowStartRequest workflowStartRequest = getWorkflowStartRequest(flowApiStartRequest, flowDefinitionId);
        return workflowControlApi.start(workflowStartRequest);
    }

    @Override
    public RuntimeInstance startByDefinitionId(FlowDefinitionStartRequest flowStartRequest) {

        if (flowStartRequest == null) {
            throw new WorkflowException(BusinessLinkExceptionEnum.PARAM_EMPTY, "整体");
        }
        if (ObjectUtil.isEmpty(flowStartRequest.getFlowDefinitionId())) {
            throw new WorkflowException(BusinessLinkExceptionEnum.PARAM_EMPTY, "流程定义id");
        }

        flowStartRequest.setWorkflowStartType(WorkflowStartTypeEnum.API_START.getCode());
        WorkflowStartRequest workflowStartRequest = getWorkflowStartRequest(flowStartRequest, flowStartRequest.getFlowDefinitionId());
        return workflowControlApi.start(workflowStartRequest);
    }

    @Override
    public List<Long> getUserWaitTodoTaskInstanceIdList(Long userId) {
        if (ObjectUtil.isEmpty(userId)) {
            return new ArrayList<>();
        }

        List<RuTask> userTaskList = this.ruTaskService.getUserProcessingAndHandlingTaskList(userId, null);
        if (ObjectUtil.isEmpty(userTaskList)) {
            return new ArrayList<>();
        }
        return userTaskList.stream().filter(Objects::nonNull).map(RuTask::getInstanceId).collect(Collectors.toList());
    }

    @Override
    public List<RuTask> getInstanceRunningTasks(Long instanceId, Long userId) {
        if (ObjectUtil.isEmpty(instanceId) || ObjectUtil.isEmpty(userId)) {
            return new ArrayList<>();
        }
        return this.ruTaskService.getUserProcessingAndHandlingTaskList(userId, instanceId);
    }

    @Override
    public RuTask getUserInstanceTask(Long instanceId) {
        List<RuTask> instanceRunningTasks = this.getInstanceRunningTasks(instanceId, LoginContext.me().getLoginUser().getUserId());
        if (ObjectUtil.isEmpty(instanceRunningTasks)) {
            return null;
        } else {
            return instanceRunningTasks.get(0);
        }
    }

    @Override
    public void finishInstanceRunningTask(List<Long> instanceIdList) {
        if (ObjectUtil.isEmpty(instanceIdList)) {
            return;
        }
        LambdaUpdateWrapper<RuTask> queryWrapper = new LambdaUpdateWrapper<>();
        queryWrapper.in(RuTask::getInstanceId, instanceIdList);
        queryWrapper.in(RuTask::getTaskStatus, TaskStatusEnum.WAIT_TO_START.getCode(), TaskStatusEnum.PROCESSING.getCode(), TaskStatusEnum.START.getCode());
        queryWrapper.set(RuTask::getTaskStatus, TaskStatusEnum.CLOSE.getCode());
        this.ruTaskService.update(queryWrapper);
    }

    private static WorkflowStartRequest getWorkflowStartRequest(FlowApiStartRequest flowApiStartRequest, Long flowDefinitionId) {
        WorkflowStartRequest workflowStartRequest = new WorkflowStartRequest();
        workflowStartRequest.setWorkflowStartType(flowApiStartRequest.getWorkflowStartType());
        workflowStartRequest.setDefinitionId(flowDefinitionId);
        workflowStartRequest.setInstanceVariable(flowApiStartRequest.getInstanceVariable());
        workflowStartRequest.setApplicant(flowApiStartRequest.getApplicant());
        workflowStartRequest.setApplicantOrgId(flowApiStartRequest.getApplicantOrgId());
        workflowStartRequest.setApplicantPositionId(flowApiStartRequest.getApplicantPositionId());
        return workflowStartRequest;
    }

}
