package com.testor.module.wf;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.testor.common.core.utils.StringUtils;
import com.testor.module.wf.vo.ZlmyProcessInsListRequest;
import com.tongtech.tfw.backend.common.biz.constants.BizConstants;
import com.tongtech.tfw.backend.common.biz.models.BaseResponse;
import com.tongtech.tfw.backend.common.biz.models.BaseResponseList;
import com.tongtech.tfw.backend.core.helper.ObjectHelper;
import com.tongtech.tfw.backend.core.helper.StringHelper;
import com.tongtech.tfw.workflow.apis.instance.model.domain.ActHiProcinst;
import com.tongtech.tfw.workflow.apis.instance.model.dto.ProcessInsListResponse;
import com.tongtech.tfw.workflow.apis.instance.service.ActHiProcinstService;
import com.tongtech.tfw.workflow.service.TfwCommonService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.codehaus.groovy.runtime.typehandling.IntegerMath;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.runtime.ActivityInstance;
import org.flowable.engine.runtime.ActivityInstanceQuery;
import org.flowable.engine.runtime.ProcessInstance;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Collectors;

/**
 * @author caq
 * @date 2024/12/3
 * @description TODO
 */
@RestController
@Api(
        value = "Process Instance Controller",
        tags = {"WF流程实例管理"}
)
@RequestMapping({"/zlmy/process-instance"})
public class ZlmyProcessInstanceController {

    private static final Logger log = LoggerFactory.getLogger(ZlmyProcessInstanceController.class);

    @Autowired
    private ActHiProcinstService actHiProcinstService;
    @Autowired
    private RuntimeService runtimeService;
    @Autowired
    private TfwCommonService tfwCommonService;


    @ApiOperation(
            value = "运行中流程列表",
            notes = "List Process Instance"
    )
    @GetMapping({"/list"})
    public BaseResponse<BaseResponseList<ProcessInsListResponse>> processInsList(ZlmyProcessInsListRequest processInsListRequest) {
        String assigneeName = processInsListRequest.getAssigneeName();
        if(StringUtils.isNotBlank(assigneeName)) {
            return this.findList(processInsListRequest);
        }else {
            return this.findListNOAssigneeName(processInsListRequest);
        }
    }


    private BaseResponse<BaseResponseList<ProcessInsListResponse>> findListNOAssigneeName(ZlmyProcessInsListRequest processInsListRequest) {
        BaseResponse<BaseResponseList<ProcessInsListResponse>> baseResponse = new BaseResponse();
        Long page = StringHelper.isEmpty(processInsListRequest.getPage()) ? BizConstants.PAGE : Long.valueOf(processInsListRequest.getPage());
        Long limit = StringHelper.isEmpty(processInsListRequest.getLimit()) ? BizConstants.LIMIT : Long.valueOf(processInsListRequest.getLimit());
        Page<ActHiProcinst> resultPage = new Page(page, limit);
        QueryWrapper<ActHiProcinst> queryWrapper = new QueryWrapper();
        queryWrapper.isNull("END_TIME_");
        if (StringHelper.isNotBlank(processInsListRequest.getInstanceId())) {
            queryWrapper.eq("PROC_INST_ID_", processInsListRequest.getInstanceId());
        }
        if (StringHelper.isNotBlank(processInsListRequest.getProcessDefinitionName())) {
            queryWrapper.in("PROC_DEF_ID_", this.tfwCommonService.queryDefId(processInsListRequest.getProcessDefinitionName()));
        }
        if (StringHelper.isNotBlank(processInsListRequest.getStartUser())) {
            queryWrapper.in("START_USER_ID_", this.tfwCommonService.queryUserIds(processInsListRequest.getStartUser()));
        }
        queryWrapper.orderByDesc("START_TIME_");
        Page<ActHiProcinst> resultList = (Page) this.actHiProcinstService.page(resultPage, queryWrapper);
        List<ProcessInsListResponse> result = new ArrayList(resultList.getRecords().size());
        Iterator var9 = resultList.getRecords().iterator();
        while (var9.hasNext()) {
            ActHiProcinst actHiProcinst = (ActHiProcinst) var9.next();
            ProcessInstance process = (ProcessInstance) this.runtimeService.createProcessInstanceQuery().processInstanceId(actHiProcinst.getProcInstId()).singleResult();
            if (ObjectHelper.isNotEmpty(process)) {
                ProcessInsListResponse processInsListResponse = new ProcessInsListResponse(process);
                processInsListResponse.setStartUser(this.tfwCommonService.queryUserName(processInsListResponse.getStartUser()));
                processInsListResponse.setProcessDefinitionName(this.tfwCommonService.queryDefName(processInsListResponse.getProcessDefinitionId()));
                List<ActivityInstance> actList = ((ActivityInstanceQuery) this.runtimeService.createActivityInstanceQuery().processInstanceId(actHiProcinst.getProcInstId()).activityType("userTask").orderByActivityInstanceStartTime().desc()).list();
                if (!actList.isEmpty()) {
                    ActivityInstance activityInstance = (ActivityInstance) actList.get(0);
                    processInsListResponse.setCurrentTaskName(activityInstance.getActivityName());
                    if (StringHelper.isNotBlank(activityInstance.getAssignee())) {
                        processInsListResponse.setAssigneeName(this.tfwCommonService.queryUserName(activityInstance.getAssignee()));
                    }
                }
                result.add(processInsListResponse);
            }
        }
        if (StringHelper.isNotBlank(processInsListRequest.getAssigneeName())) {
            result = result.stream().filter((x) -> x.getAssigneeName() != null && x.getAssigneeName().equals(processInsListRequest.getAssigneeName())).collect(Collectors.toList());
        }
        BaseResponseList<ProcessInsListResponse> responseListBaseResponse = new BaseResponseList();
        responseListBaseResponse.setData(result);
        responseListBaseResponse.setTotal(resultList.getTotal());
        baseResponse.setData(responseListBaseResponse);
        return baseResponse;
    }


    private BaseResponse<BaseResponseList<ProcessInsListResponse>> findList(ZlmyProcessInsListRequest processInsListRequest) {
        BaseResponse<BaseResponseList<ProcessInsListResponse>> baseResponse = new BaseResponse();
        Long page = StringHelper.isEmpty(processInsListRequest.getPage()) ? BizConstants.PAGE : Long.valueOf(processInsListRequest.getPage());
        Long limit = StringHelper.isEmpty(processInsListRequest.getLimit()) ? BizConstants.LIMIT : Long.valueOf(processInsListRequest.getLimit());

        String assigneeName = processInsListRequest.getAssigneeName();

        Long page1 = 1L;
        Long limit1 = Long.MAX_VALUE;
        Page<ActHiProcinst> resultPage = new Page(page1, limit1);
        QueryWrapper<ActHiProcinst> queryWrapper = new QueryWrapper();
        queryWrapper.isNull("END_TIME_");
        if (StringHelper.isNotBlank(processInsListRequest.getInstanceId())) {
            queryWrapper.eq("PROC_INST_ID_", processInsListRequest.getInstanceId());
        }
        if (StringHelper.isNotBlank(processInsListRequest.getProcessDefinitionName())) {
            queryWrapper.in("PROC_DEF_ID_", this.tfwCommonService.queryDefId(processInsListRequest.getProcessDefinitionName()));
        }
        if (StringHelper.isNotBlank(processInsListRequest.getStartUser())) {
            queryWrapper.in("START_USER_ID_", this.tfwCommonService.queryUserIds(processInsListRequest.getStartUser()));
        }
        queryWrapper.orderByDesc("START_TIME_");
        Page<ActHiProcinst> hiProcinstPage = this.actHiProcinstService.page(resultPage, queryWrapper);
        CopyOnWriteArrayList<ProcessInsListResponse> result = new CopyOnWriteArrayList<>();
        hiProcinstPage.getRecords().parallelStream().forEach(actHiProcinst -> {

            ProcessInstance process = this.runtimeService.createProcessInstanceQuery().processInstanceId(actHiProcinst.getProcInstId()).singleResult();
            if (ObjectHelper.isNotEmpty(process)) {
                ProcessInsListResponse processInsListResponse = new ProcessInsListResponse(process);
                processInsListResponse.setStartUser(this.tfwCommonService.queryUserName(processInsListResponse.getStartUser()));
                processInsListResponse.setProcessDefinitionName(this.tfwCommonService.queryDefName(processInsListResponse.getProcessDefinitionId()));
                List<ActivityInstance> actList = (this.runtimeService.createActivityInstanceQuery().processInstanceId(actHiProcinst.getProcInstId()).activityType("userTask").orderByActivityInstanceStartTime().desc()).list();
                if (!actList.isEmpty()) {
                    ActivityInstance activityInstance = actList.get(0);
                    processInsListResponse.setCurrentTaskName(activityInstance.getActivityName());
                    if (StringHelper.isNotBlank(activityInstance.getAssignee())) {
                        String s = this.tfwCommonService.queryUserName(activityInstance.getAssignee());
                        if (StringHelper.isNotBlank(s) && s.equals(assigneeName)) {
                            processInsListResponse.setAssigneeName(s);
                            result.add(processInsListResponse);
                        }
                    }
                }

            }
        });

        BaseResponseList<ProcessInsListResponse> responseListBaseResponse = new BaseResponseList();
        if (page < 1 || limit < 1) {
            return baseResponse;
        }
        // 计算起始索引
        int start = (int) ((page - 1) * limit);
        // 计算结束索引
        int end = (int) Math.min(start + limit - 1, result.size() - 1);
        // 截取列表并返回
        ArrayList<ProcessInsListResponse> processInsListResponses = new ArrayList<>(result.subList(start, end + 1));
        responseListBaseResponse.setData(processInsListResponses);
        responseListBaseResponse.setTotal(result.size());
        baseResponse.setData(responseListBaseResponse);
        return baseResponse;
    }


}
