package com.ningdatech.pmapi.todocenter.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ningdatech.pmapi.common.helper.UserInfoHelper;
import com.ningdatech.pmapi.projectlib.model.entity.Project;
import com.ningdatech.pmapi.projectlib.model.entity.ProjectInst;
import com.ningdatech.pmapi.projectlib.service.IProjectInstService;
import com.ningdatech.pmapi.projectlib.service.IProjectService;
import com.ningdatech.pmapi.todocenter.handle.PassHandle;
import com.ningdatech.pmapi.todocenter.handle.WithDrawHandle;
import com.ningdatech.pmapi.todocenter.manage.HandlerManage;
import com.ningdatech.pmapi.todocenter.model.req.ProcessDetailReq;
import com.ningdatech.pmapi.todocenter.model.vo.ProcessProgressDetailVo;
import com.ningdatech.pmapi.todocenter.service.ITodoService;
import com.ningdatech.pmapi.todocenter.utils.BuildUserUtils;
import com.ningdatech.pmapi.user.security.auth.model.UserFullInfoDTO;
import com.ningdatech.pmapi.user.security.auth.model.UserInfoDetails;
import com.ningdatech.pmapi.user.util.LoginUserUtil;
import com.wflow.workflow.bean.process.ProgressNode;
import com.wflow.workflow.bean.process.enums.NodeTypeEnum;
import com.wflow.workflow.bean.vo.ProcessProgressVo;
import com.wflow.workflow.service.ProcessInstanceService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Objects;

/**
 * @Classname TodoService
 * @Description
 * @Date 2023/7/25 15:41
 * @Author PoffyZhang
 */
@Service
@AllArgsConstructor
@Slf4j
public class TodoServiceImpl implements ITodoService {

    private final ProcessInstanceService processInstanceService;

    private final BuildUserUtils buildUserUtils;

    private final UserInfoHelper userInfoHelper;

    private final WithDrawHandle withDrawHandle;

    private final PassHandle passHandle;

    private final IProjectService projectService;

    private final IProjectInstService projectInstService;

    /**
     * 查询流程表单数据及审批的进度步骤
     *
     * @param request 请求参数
     * @return 流程进度及表单详情
     */
    @Override
    public ProcessProgressDetailVo getProcessDetail(ProcessDetailReq request) {
        String employeeCode = LoginUserUtil.loginUserDetail().getEmployeeCode();
        String instanceId = request.getInstanceId();
        String nodeId = request.getNodeId();
        Long projectId = request.getProjectId();
        String taskId = request.getTaskId();
        ProcessProgressVo progressInstanceDetail = processInstanceService.getProgressInstanceDetail(nodeId, instanceId,taskId);

        if(Objects.isNull(progressInstanceDetail)){
            return null;
        }

        List<ProgressNode> progressInfo = progressInstanceDetail.getProgressInfo();
        Boolean isHighLine = Boolean.FALSE;
        if (CollUtil.isNotEmpty(progressInfo)){
            buildUserUtils.buildUserByProcessInfo(progressInfo);
            isHighLine = checkHighLine(progressInfo,taskId,LoginUserUtil.loginUserDetail());
        }
        ProcessProgressDetailVo res = new ProcessProgressDetailVo();
        res.setProcessProgressVo(progressInstanceDetail);
        res.setStatus(progressInstanceDetail.getStatus());
        res.setProjectId(projectId);
        res.setCanWithdraw(withDrawHandle.checkCanWithdraw(instanceId,progressInstanceDetail,request.getTaskId()));
        res.setIsHighLine(isHighLine);
        passHandle.checkCanPassOrSeal(request.getInstanceId(),request.getTaskId(),employeeCode,res);
        //是不是被 驳回|退回
        res.setIsChange(isChangeRecord(projectId));
        return res;
    }

    /**
     * 筛选 当前登录人 是不是 上级条线单位的审批
     * @param progressInfo
     * @param taskId
     * @param user
     * @return
     */
    private Boolean checkHighLine(List<ProgressNode> progressInfo, String taskId, UserInfoDetails user) {
        if(CollUtil.isEmpty(progressInfo)){
            return Boolean.FALSE;
        }

        final Boolean[] res = {Boolean.FALSE};
        progressInfo.forEach(p -> {
            //如果是 子流程
            if(Objects.nonNull(p.getNodeType()) && NodeTypeEnum.SUB.name().equals(p.getNodeType().name())){
                //如果不是上级条线单位 根本不用理
                if(!p.getIsHighLine()){
                    return;
                }
                List<ProgressNode> children = p.getChildren();
                ProgressNode progressNode = children.get(0);
                String userId = progressNode.getUserId();
                if(StringUtils.isBlank(userId)){
                    return;
                }
                UserFullInfoDTO userFullInfoDTO = userInfoHelper.getUserFullInfoByEmployeeCode(userId);
                if(Objects.nonNull(userFullInfoDTO) && user.getEmpPosUnitCode()
                        .equals(userFullInfoDTO.getEmpPosUnitCode())){
                    //说明是此单位的人
                    //那么要去看 taskId 是不是 在这个单位内的任务
                    Boolean isContainsTask = HandlerManage.checkIsContainsTask(children,taskId);
                    if(isContainsTask){
                        res[0] =  Boolean.TRUE;
                        return;
                    }
                }
            }
        });
        return res[0];
    }

    /**
     * 判断 当前项目是不是被驳回 或者 退回过
     * @param projectId
     * @return
     */
    @Override
    public Boolean isChangeRecord(Long projectId) {
        //1.先判断下 项目存不存在
        Project project = projectService.getById(projectId);
        if(Objects.isNull(project)){
            return Boolean.FALSE;
        }

        List<Long> projectIds = projectService.getAllVersionProjectId(project);
        //2.要判断 项目在当前状态 有没有被驳回和退回过
        //当前项目状态流程的 实例 看看是不是有2个以上 有2个说明 有退回 驳回
        List<ProjectInst> pis = projectInstService.list(Wrappers.lambdaQuery(ProjectInst.class)
                .in(ProjectInst::getProjectId, projectIds)
                .orderByDesc(ProjectInst::getInstType)
                .last("limit 2"));
        if(CollUtil.isEmpty(pis)){
            return Boolean.FALSE;
        }
        //判断 项目关联的最新的2个实例 如果类型不匹配 也不属于是变更了
        //还要看 项目当前的流程实例code 是不是 关联的最新实例
        if( pis.size() < 2 ||
                !pis.get(0).getInstCode().equals(project.getInstCode()) ||
                pis.get(0).getProjectId().equals(pis.get(1).getProjectId()) ||
                !pis.get(0).getInstType().equals(pis.get(1).getInstType())) {
            return Boolean.FALSE;
        }

        return Boolean.TRUE;
    }
}
