package com.yeejoin.amos.boot.module.jg.biz.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.map.MapBuilder;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.pagehelper.util.StringUtil;
import com.yeejoin.amos.boot.biz.common.bo.CompanyBo;
import com.yeejoin.amos.boot.biz.common.bo.ReginParams;
import com.yeejoin.amos.boot.biz.common.utils.RedisKey;
import com.yeejoin.amos.boot.biz.common.utils.RedisUtils;
import com.yeejoin.amos.boot.module.jg.api.dto.*;
import com.yeejoin.amos.boot.module.jg.api.entity.JgEquipTransfer;
import com.yeejoin.amos.boot.module.jg.api.entity.JgEquipTransferEq;
import com.yeejoin.amos.boot.module.jg.api.entity.JgRegistrationHistory;
import com.yeejoin.amos.boot.module.jg.api.enums.BusinessTypeEnum;
import com.yeejoin.amos.boot.module.jg.api.enums.CompanyTypeEnum;
import com.yeejoin.amos.boot.module.jg.api.mapper.JgEquipTransferEqMapper;
import com.yeejoin.amos.boot.module.jg.api.mapper.JgEquipTransferMapper;
import com.yeejoin.amos.boot.module.jg.api.mapper.JgRegistrationHistoryMapper;
import com.yeejoin.amos.boot.module.jg.api.service.IJgEquipTransferService;
import com.yeejoin.amos.boot.module.jg.api.service.IJgInstallationNoticeService;
import com.yeejoin.amos.boot.module.jg.api.vo.SortVo;
import com.yeejoin.amos.boot.module.jg.api.vo.tableDataExportVo.EquipTransferVo;
import com.yeejoin.amos.boot.module.jg.biz.context.EquipUsedCheckStrategyContext;
import com.yeejoin.amos.boot.module.jg.biz.feign.TzsServiceFeignClient;
import com.yeejoin.amos.boot.module.jg.biz.service.ICompensateFlowDataOfRedis;
import com.yeejoin.amos.boot.module.jg.biz.service.IIdxBizJgRegisterInfoService;
import com.yeejoin.amos.boot.module.ymt.api.common.BaseException;
import com.yeejoin.amos.boot.module.ymt.api.enums.ApplicationFormTypeEnum;
import com.yeejoin.amos.boot.module.ymt.api.enums.FlowStatusEnum;
import com.yeejoin.amos.feign.systemctl.model.TaskV2Model;
import com.yeejoin.amos.feign.workflow.model.ActWorkflowBatchDTO;
import com.yeejoin.amos.feign.workflow.model.ActWorkflowStartDTO;
import com.yeejoin.amos.feign.workflow.model.ProcessTaskDTO;
import com.yeejoin.amos.feign.workflow.model.TaskResultDTO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.typroject.tyboot.core.foundation.context.RequestContext;
import org.typroject.tyboot.core.rdbms.service.BaseService;
import org.typroject.tyboot.core.restful.exception.instance.BadRequest;
import org.typroject.tyboot.core.restful.utils.ResponseModel;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

/**
 * 设备移交服务实现类
 *
 * @author LiuLin
 * @date 2023-12-20
 */
@Slf4j
@Service
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class JgEquipTransferServiceImpl extends BaseService<JgEquipTransferDto, JgEquipTransfer, JgEquipTransferMapper> implements IJgEquipTransferService, ICompensateFlowDataOfRedis<JgEquipTransfer> {
    private static final String EQUIP_TRANSFER_PROCESS_KEY = "equipmentHandover";
    private final List<String> NOT_FLOWING_STATE = Arrays.asList("6610", "6614", "6615", "6617", "6616");

    private static final String SUBMIT_TYPE_FLOW = "1";
    private final JgEquipTransferEqMapper jgEquipTransferEqMapper;
    private final JgEquipTransferEqServiceImpl equipTransferEqService;
    private final RedisUtils redisUtils;
    private final TzsServiceFeignClient tzsServiceFeignClient;

    private final CmWorkflowServiceImpl cmWorkflowService;
    private final IJgInstallationNoticeService jrmInstallationNoticeService;
    private final IIdxBizJgRegisterInfoService idxBizJgRegisterInfoService;

    @Lazy
    private final CommonServiceImpl commonService;

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private JgRegistrationHistoryMapper jgRegistrationHistoryMapper;

    /**
     * 保存和保存并提交
     *
     * @param submitType    保存或保存并提交
     * @param jsonObjectMap 设备移交和设备信息
     * @param reginParams   redis信息
     */
    @Transactional(rollbackFor = {Exception.class, BaseException.class})
    public List<JgEquipTransfer> saveTransfer(String submitType, JSONObject jsonObjectMap, ReginParams reginParams) {
        JgEquipTransferDto model = JSON.parseObject(JSONObject.toJSONString(jsonObjectMap), JgEquipTransferDto.class);

        convertField(model);
        List<Map<String, Object>> deviceList = model.getDeviceList();
        if (CollectionUtils.isEmpty(deviceList)) {
            throw new BadRequest("请选择设备!");
        }

        //获取申请单编号
        ResponseModel<List<String>> listResponseModel = tzsServiceFeignClient.applicationFormCode(ApplicationFormTypeEnum.getCode.get(String.valueOf(jsonObjectMap.get("businessCode"))), deviceList.size());
        this.handleResponseModel(listResponseModel, "告知单获取失败: ");
        List<String> applyNoList = listResponseModel.getResult();
        this.handleApplyNoList(applyNoList);

        //启动工作流
        List<WorkflowResultDto> workflowResultList = this.startWorkFlow(model.getInstallUnitCreditCode(), submitType, deviceList);

        List<JgEquipTransfer> transferList = new ArrayList<>();
        List<JgEquipTransferEq> equipTransferEqList = new ArrayList<>();
        IntStream.range(0, deviceList.size()).forEach(i -> {
            Map<String, Object> obj = deviceList.get(i);
            String applyNo = applyNoList.get(i);

            JgEquipTransferEq jgEquipTransferEq = buildJgEquipTransferEq(obj, applyNo);
            JgEquipTransfer transfer = buildJgEquipTransfer(model, applyNo, reginParams, submitType, workflowResultList, i);
            transfer.setSupervisoryCode(String.valueOf(obj.get("SUPERVISORY_CODE")));
            transfer.setEquList(Objects.toString(obj.get("EQU_LIST"), ""));
            transfer.setEquDefine(Objects.toString(obj.get("EQU_DEFINE"), ""));
            transfer.setEquCategory(Objects.toString(obj.get("EQU_CATEGORY"), ""));
            transfer.setProductName(Objects.toString(obj.get("PRODUCT_NAME"), ""));
            transfer.setUseRegistCode(Objects.toString(obj.get("USE_ORG_CODE"), ""));
            transfer.setUseRegistCode(Objects.toString(obj.get("USE_ORG_CODE"), ""));
            transfer.setUseInnerCode(Objects.toString(obj.get("USE_INNER_CODE"), ""));
            transfer.setEquAddress(Objects.toString(obj.get("ADDRESS"), ""));
            transfer.setEquCode(Objects.toString(obj.get("EQU_CODE"), ""));
            transferList.add(transfer);
            equipTransferEqList.add(jgEquipTransferEq);
        });

        baseMapper.insertBatchSomeColumn(transferList);
        if (SUBMIT_TYPE_FLOW.equals(submitType)) {
            this.buildTask(transferList, workflowResultList);
        } else {
            //批量暂存
            this.saveTempTransfer(transferList);
        }

        List<JgEquipTransferEq> jgEquipTransferEqList = this.buildJgEquipTransferEqList(equipTransferEqList, transferList);
        jgEquipTransferEqMapper.insertBatchSomeColumn(jgEquipTransferEqList);
        this.updateRedisBatch(transferList);
        // 创建历史数据
        this.saveOrUpdateHisDataBatch(jgEquipTransferEqList);
        if (SUBMIT_TYPE_FLOW.equals(submitType)) {//放在最后面防止前面有异常
            //如果是提交，用于校验设备是否已经在流程中，如果不在标记设备已经在流程中
            CompanyBo company = reginParams.getCompany();
            jgEquipTransferEqList.forEach(equipTransferEq -> EquipUsedCheckStrategyContext.getUsedStrategy(EQUIP_TRANSFER_PROCESS_KEY)
                    .equipRepeatUsedCheck(equipTransferEq.getEquId(), CompanyTypeEnum.INDIVIDUAL.getName().equals(company.getCompanyType()) ?
                            company.getCompanyCode().split("_")[1] :
                            company.getCompanyCode()));
        }
        return transferList;
    }

    /**
     * 删除redis校验重复引用设备的数据
     */
    private void delRepeatUseEquipData(Long id, String status, String companyCode) {
        List<JgEquipTransferEq> list = equipTransferEqService.lambdaQuery().eq(JgEquipTransferEq::getEquipTransferId, id).list();
        // 获取单位变更设备列表
        if (CollectionUtils.isEmpty(list)) {
            return;
        }
        List<String> records = list.stream().map(JgEquipTransferEq::getEquId).collect(Collectors.toList());
        if (NOT_FLOWING_STATE.contains(status)) {
            EquipUsedCheckStrategyContext.getUsedStrategy(EQUIP_TRANSFER_PROCESS_KEY)
                    .delDataForCheckEquipRepeatUsed(records, companyCode);
        }
    }

    private void saveOrUpdateHisDataBatch(List<JgEquipTransferEq> jgEquipTransferEqList) {
        jgEquipTransferEqList.forEach(j -> {
            commonService.saveOrUpdateHistory(BusinessTypeEnum.JG_EQUIPMENT_HANDOVER.getName(), getEquipInfoJson(j.getEquId()), j.getEquId(), j.getEquipTransferId());
        });
    }

    private JSON getEquipInfoJson(String record) {
        Map<String, Object> equipMap = idxBizJgRegisterInfoService.getDetailFieldCamelCaseByRecord(record);
        ;
        equipMap.remove("useUnitCreditCode");
        return new JSONObject(equipMap);
    }


    private void updateRedisBatch(List<JgEquipTransfer> transferList) {
        transferList.stream().filter(n -> StringUtil.isNotEmpty(n.getInstanceId())).forEach(jgEquipTransfer -> {
            commonService.saveExecuteFlowData2Redis(jgEquipTransfer.getInstanceId(), this.buildInstanceRuntimeData(jgEquipTransfer));
        });
    }


    /**
     * 批量暂存
     *
     * @param transferList 移交信息
     */
    private void saveTempTransfer(List<JgEquipTransfer> transferList) {
        if (CollectionUtils.isEmpty(transferList)) {
            return;
        }

        List<TaskModelDto> taskModelDtoList = transferList.stream().map(this::buildTempTaskModelDto).collect(Collectors.toList());
        commonService.buildTaskModel(taskModelDtoList);
    }

    private TaskModelDto buildTempTaskModelDto(JgEquipTransfer item) {
        return TaskModelDto.builder()
                .model(item)
                .taskContent(String.format("来自%s【%s】的业务办理，【申请单号：%s】", item.getEquList(), Objects.toString(item.getSupervisoryCode(), ""), item.getApplyNo()))
                .taskCode(item.getApplyNo())
                .taskType(BusinessTypeEnum.JG_EQUIPMENT_HANDOVER.getCode())
                .relationId(item.getSequenceNbr() + "")
                .build();
    }

    /**
     * 上个代办改为已办
     *
     * @param transfer 设备信息
     * @return 代办信息
     */
    private TaskV2Model updateLastTodo(JgEquipTransfer transfer, FlowStatusEnum statusEnum) {
        return commonService.updateTaskModel(MapBuilder.<String, Object>create()
                .put("taskStatus", statusEnum.getCode())
                .put("taskStatusLabel", statusEnum.getName())
                .put("flowStatus", statusEnum.getCode())
                .put("flowStatusLabel", statusEnum.getName())
                .put("relationId", transfer.getInstanceId())
                .put("model", transfer)
                .build());
    }

    /**
     * 组装代办消息
     *
     * @param item              设备移交信息
     * @param workflowResultDto 工作流返回信息
     * @return 代办信息
     */
    private TaskModelDto buildTaskModelDto(JgEquipTransfer item, WorkflowResultDto workflowResultDto) {
        TaskMessageDto taskMessageDto = new TaskMessageDto();
        BeanUtil.copyProperties(item, taskMessageDto);
        return TaskModelDto.builder()
                .flowCreateDate(item.getCreateDate())
                .taskName(workflowResultDto.getNextTaskName())
                .taskCode(item.getApplyNo())
                .taskType(BusinessTypeEnum.JG_EQUIPMENT_HANDOVER.getCode())
                .taskTypeLabel(BusinessTypeEnum.JG_EQUIPMENT_HANDOVER.getName())
                .relationId(workflowResultDto.getInstanceId())
                .executeUserIds(workflowResultDto.getNextExecutorUserIds())
                .taskStatus(FlowStatusEnum.TO_BE_PROCESSED.getCode())
                .taskStatusLabel(FlowStatusEnum.TO_BE_PROCESSED.getName())
                .flowStatus(FlowStatusEnum.TO_BE_PROCESSED.getCode())
                .flowCode(workflowResultDto.getNextTaskId())
                .flowStatusLabel(FlowStatusEnum.TO_BE_PROCESSED.getName())
                .taskContent(String.format("来自%s【%s】的业务办理，【申请单号：%s】", item.getEquList(), Objects.toString(item.getSupervisoryCode(), ""), item.getApplyNo()))
                .taskDesc(String.format("来自%s【%s】的业务办理，【申请单号：%s】", item.getEquList(), Objects.toString(item.getSupervisoryCode(), ""), item.getApplyNo()))
                .startUserId(item.getCreateUserId())
                .startUser(item.getCreateUserName())
                .startUserCompanyName(item.getCreateUserCompanyName())
                .startDate(item.getCreateDate())
                .model(taskMessageDto)
                .nextExecuteUser(item.getNextExecuteIds())
                .build();
    }

    /**
     * 创建新代办
     *
     * @param transfer          设备信息
     * @param workflowResultDto 工作流信息
     * @param taskV2Model       代办信息
     */
    private void createNewTodo(JgEquipTransfer transfer, WorkflowResultDto workflowResultDto, TaskV2Model taskV2Model, FlowStatusEnum statusEnum) {
        TaskMessageDto taskMessageDto = new TaskMessageDto();
        BeanUtil.copyProperties(transfer, taskMessageDto);

        ReginParams reginParams = JSONObject.parseObject(redisUtils.get(RedisKey.buildReginKey(RequestContext.getExeUserId(), RequestContext.getToken())).toString(), ReginParams.class);
        TaskModelDto taskModelDto = TaskModelDto.builder()
                .flowCreateDate(taskV2Model.getFlowCreateDate())
                .taskName(workflowResultDto.getNextTaskName())
                .taskCode(taskV2Model.getTaskCode())
                .taskType(taskV2Model.getTaskType())
                .taskTypeLabel(taskV2Model.getTaskTypeLabel())
                .relationId(taskV2Model.getRelationId())
                .executeUserIds(workflowResultDto.getNextExecutorUserIds())
                .taskStatusLabel(statusEnum.getName())
                .flowStatus(statusEnum.getCode())
                .flowCode(workflowResultDto.getNextTaskId())
                .flowStatusLabel(statusEnum.getName())
                .taskContent(String.format("来自%s【%s】的业务办理，【申请单号：%s】", transfer.getEquList(), transfer.getSupervisoryCode(), transfer.getApplyNo()))
                .taskDesc(String.format("来自%s【%s】的业务办理，【申请单号：%s】", transfer.getEquList(), transfer.getSupervisoryCode(), transfer.getApplyNo()))
                .startUserCompanyName(reginParams.getCompany().getCompanyName())
                .startUserId(taskV2Model.getStartUserId())
                .startUser(taskV2Model.getStartUser())
                .startDate(taskV2Model.getStartDate())
                .pageType(statusEnum.getCode() == 6614 ? "edit" : "look")
                .model(taskMessageDto)
                .nextExecuteUser(workflowResultDto.getNextExecutorRoleIds())
                .build();
        commonService.buildTaskModel(Collections.singletonList(taskModelDto));
    }

    /**
     * 暂存
     *
     * @param submitType       保存或保存并提交
     * @param equipTransferDto 设备移交和设备信息
     * @param op
     * @param reginParams
     * @return 设备信息
     */
    @Transactional(rollbackFor = {Exception.class, BaseException.class})
    public JgEquipTransferDto updateEquipTransfer(String submitType, JgEquipTransferDto equipTransferDto, String op, ReginParams reginParams) {
        if (Objects.isNull(equipTransferDto) || StringUtils.isEmpty(submitType)) {
            throw new IllegalArgumentException("参数不能为空");
        }

        this.convertField(equipTransferDto);
        JgEquipTransfer transfer = this.getById(equipTransferDto.getSequenceNbr());

        if (SUBMIT_TYPE_FLOW.equals(submitType)) {
            if (!StringUtils.hasText(equipTransferDto.getInstanceId())) {
                // 发起流程
                ActWorkflowBatchDTO actWorkflowBatchDTO = new ActWorkflowBatchDTO();
                List<ActWorkflowStartDTO> list = new ArrayList<>();
                ActWorkflowStartDTO dto = new ActWorkflowStartDTO();
                dto.setProcessDefinitionKey(EQUIP_TRANSFER_PROCESS_KEY);
                dto.setBusinessKey(equipTransferDto.getSequenceNbr().toString());
                dto.setCompleteFirstTask(Boolean.TRUE);
                dto.setNextExecuteUserCompanyCode(equipTransferDto.getInstallUnitCreditCode());
                list.add(dto);
                actWorkflowBatchDTO.setProcess(list);
                ProcessTaskDTO processTaskDTO = cmWorkflowService.startBatch(actWorkflowBatchDTO).get(0);
                // 提取节点等信息
                WorkflowResultDto workflowResultDto = commonService.buildWorkFlowInfo(Collections.singletonList(processTaskDTO)).get(0);
                BeanUtils.copyProperties(equipTransferDto, transfer);
                if (!ObjectUtils.isEmpty(transfer.getInstanceStatus())) {
                    transfer.setInstanceStatus(transfer.getInstanceStatus() + "," + workflowResultDto.getNextExecutorRoleIds());
                } else {
                    transfer.setInstanceStatus(workflowResultDto.getNextExecutorRoleIds());
                }
                transfer.setPromoter(RequestContext.getExeUserId());
                transfer.setNextExecuteIds(String.join(",", workflowResultDto.getNextExecutorRoleIds()));
                transfer.setApplyStatus(String.valueOf(FlowStatusEnum.TO_BE_PROCESSED.getCode()));
                transfer.setNextTaskId(workflowResultDto.getNextTaskId());
                transfer.setInstanceId(workflowResultDto.getInstanceId());
                transfer.setNextExecuteUserIds(workflowResultDto.getNextExecutorUserIds());

                updateById(transfer);
                //删除暂存
                commonService.deleteTasksByRelationId(transfer.getSequenceNbr() + "");

                // 如果为保存并提交，则创建代办
                this.buildTask(Collections.singletonList(transfer), Collections.singletonList(workflowResultDto));
            } else {
                TaskResultDTO dto = new TaskResultDTO();
                dto.setResultCode("approvalStatus");
                dto.setTaskId(transfer.getNextTaskId());
                HashMap<String, Object> commMap = new HashMap<>();
                if (transfer.getApplyStatus().equals("6614") || transfer.getApplyStatus().equals("6615")) {
                    commMap.put("approvalStatus", "提交");
                } else {
                    commMap.put("approvalStatus", op);
                }
                dto.setVariable(commMap);
                dto.setNextExecuteUserCompanyCode(transfer.getInstallUnitCreditCode());
                ProcessTaskDTO processTaskDTO = cmWorkflowService.completeOrReject(transfer.getNextTaskId(), dto, op);
                // 提取节点等信息
                WorkflowResultDto workflowResultDto = commonService.buildWorkFlowInfo(Collections.singletonList(processTaskDTO)).get(0);
                BeanUtils.copyProperties(equipTransferDto, transfer);

                if (!ObjectUtils.isEmpty(transfer.getInstanceStatus())) {
                    transfer.setInstanceStatus(transfer.getInstanceStatus() + "," + workflowResultDto.getNextExecutorRoleIds());
                } else {
                    transfer.setInstanceStatus(workflowResultDto.getNextExecutorRoleIds());
                }
                transfer.setPromoter(RequestContext.getExeUserId());
                transfer.setNextExecuteIds(String.join(",", workflowResultDto.getNextExecutorRoleIds()));
                transfer.setApplyStatus(String.valueOf(FlowStatusEnum.TO_BE_PROCESSED.getCode()));
                transfer.setNextTaskId(workflowResultDto.getNextTaskId());
                transfer.setNextExecuteUserIds(workflowResultDto.getNextExecutorUserIds());
                //transfer.setInstanceId(workflowResultDto.getInstanceId());

                updateById(transfer);
                // 上个代办改为已办
                TaskV2Model taskV2Model = this.updateLastTodo(transfer, FlowStatusEnum.TO_BE_PROCESSED);
                // 创建新的代办
                this.createNewTodo(transfer, workflowResultDto, taskV2Model, FlowStatusEnum.TO_BE_PROCESSED);
            }
            commonService.saveExecuteFlowData2Redis(transfer.getInstanceId(), this.buildInstanceRuntimeData(transfer));
        } else {
            JgEquipTransfer equipTransfer = new JgEquipTransfer();
            BeanUtils.copyProperties(equipTransferDto, equipTransfer);
            updateById(equipTransfer);
        }
        List<JgEquipTransferEq> jgEquipTransferEqList = jgEquipTransferEqMapper.selectList(new LambdaQueryWrapper<JgEquipTransferEq>().eq(JgEquipTransferEq::getEquipTransferId, equipTransferDto.getSequenceNbr()));
        this.saveOrUpdateHisDataBatch(jgEquipTransferEqList);
        if (SUBMIT_TYPE_FLOW.equals(submitType)) {//放在最后面防止前面有异常
            //如果是提交，用于校验设备是否已经在流程中，如果不在标记设备已经在流程中
            CompanyBo company = reginParams.getCompany();
            jgEquipTransferEqList.forEach(equipTransferEq -> EquipUsedCheckStrategyContext.getUsedStrategy(EQUIP_TRANSFER_PROCESS_KEY)
                    .equipRepeatUsedCheck(equipTransferEq.getEquId(), CompanyTypeEnum.INDIVIDUAL.getName().equals(company.getCompanyType()) ?
                            company.getCompanyCode().split("_")[1] :
                            company.getCompanyCode()));
        }
        return equipTransferDto;
    }


    /**
     * 通过和驳回
     *
     * @param jgEquipTransferDto 设备信息
     * @param op                 通过或驳回
     */
    @Transactional(rollbackFor = Exception.class)
    public void accept(JgEquipTransferDto jgEquipTransferDto, String op) {
        String instanceId = jgEquipTransferDto.getInstanceId();
        String nextTaskId = jgEquipTransferDto.getNextTaskId();
        String lockKey = CommonServiceImpl.buildJgExecuteLockKey(instanceId);
        RLock lock = redissonClient.getLock(lockKey);
        try {
            boolean isLocked = lock.tryLock(0, 180, TimeUnit.SECONDS);
            // 解决并发问题：多个人同时操作一个流程（并发执行通过、驳回、撤回）
            if (!isLocked) {
                throw new BadRequest("当前流程已经被执行！请重新打开页面查看并执行！");
            }
            // 流程执行时，状态及权限校验
            commonService.checkForExecuteFlow(nextTaskId, instanceId);
            ReginParams reginParams = JSONObject.parseObject(redisUtils.get(RedisKey.buildReginKey(RequestContext.getExeUserId(), RequestContext.getToken())).toString(), ReginParams.class);
            JgEquipTransfer jgEquipTransfer = baseMapper.selectById(jgEquipTransferDto.getSequenceNbr());

            TaskResultDTO workDto = new TaskResultDTO();
            workDto.setResultCode("approvalStatus");
            workDto.setTaskId(jgEquipTransfer.getNextTaskId());
            HashMap<String, Object> commMap = new HashMap<>();
            if (jgEquipTransfer.getApplyStatus().equals("6614") || jgEquipTransfer.getApplyStatus().equals("6615")) {
                commMap.put("approvalStatus", "提交");
            } else {
                commMap.put("approvalStatus", op);
            }
            workDto.setNextExecuteUserCompanyCode("1".equals(op) ? jgEquipTransfer.getUseUnitCreditCode() : jgEquipTransfer.getInstallUnitCreditCode());
            workDto.setVariable(commMap);
            workDto.setComment(jgEquipTransferDto.getProcessAdvice());
            ProcessTaskDTO processTaskDTO = cmWorkflowService.completeOrReject(jgEquipTransfer.getNextTaskId(), workDto, op);
            // 提取节点等信息
            WorkflowResultDto workflowResultDto = commonService.buildWorkFlowInfo(Collections.singletonList(processTaskDTO)).get(0);
            jgEquipTransfer.setPromoter(reginParams.getUserModel().getUserId());
            jgEquipTransfer.setProcessAdvice(jgEquipTransferDto.getProcessAdvice());
            JgEquipTransferEq jgEquipTransferEq = jgEquipTransferEqMapper.selectOne(Wrappers.<JgEquipTransferEq>lambdaQuery().select(JgEquipTransferEq::getEquId)
                    .eq(JgEquipTransferEq::getEquipTransferId, jgEquipTransferDto.getSequenceNbr()));

            TaskV2Model taskV2Model;
            if ("0".equals(op)) {
                if (StringUtils.isEmpty(workflowResultDto.getNextExecutorRoleIds())) {
                    jgEquipTransfer.setApplyStatus(String.valueOf(FlowStatusEnum.TO_BE_FINISHED.getCode()));
                    jgEquipTransfer.setPromoter("");
                    jgEquipTransfer.setNextTaskId(null);
                    jgEquipTransfer.setAcceptDate(new Date());
                    if (jgEquipTransferEq != null) {
                        Map<String, Map<String, Object>> resultMap = MapBuilder.<String, Map<String, Object>>create()
                                .put(jgEquipTransferEq.getEquId(), MapBuilder.<String, Object>create()
                                        .put("USC_UNIT_NAME", jgEquipTransfer.getInstallUnitName())
                                        .put("USC_UNIT_CREDIT_CODE", jgEquipTransfer.getInstallUnitCreditCode())
                                        .build())
                                .build();

                        tzsServiceFeignClient.commonUpdateEsDataByIds(resultMap);
                    }
                    // 上个代办改为已办
                    this.updateLastTodo(jgEquipTransfer, FlowStatusEnum.TO_BE_FINISHED);
                } else {
                    jgEquipTransfer.setNextExecuteIds(workflowResultDto.getNextExecutorRoleIds());
                    if (!ObjectUtils.isEmpty(jgEquipTransfer.getInstanceStatus())) {
                        jgEquipTransfer.setInstanceStatus(jgEquipTransfer.getInstanceStatus() + "," + workflowResultDto.getNextExecutorRoleIds());
                    } else {
                        jgEquipTransfer.setInstanceStatus(workflowResultDto.getNextExecutorRoleIds());
                    }
                    jgEquipTransfer.setPromoter(RequestContext.getExeUserId());
                    jgEquipTransfer.setApplyStatus(String.valueOf(FlowStatusEnum.TO_BE_PROCESSED.getCode()));
                    jgEquipTransfer.setNextTaskId(workflowResultDto.getNextTaskId());
                    jgEquipTransfer.setInstanceId(workflowResultDto.getInstanceId());
                    // 上个代办改为已办
                    taskV2Model = this.updateLastTodo(jgEquipTransfer, FlowStatusEnum.TO_BE_FINISHED);
                    // 创建新的代办
                    this.createNewTodo(jgEquipTransfer, workflowResultDto, taskV2Model, FlowStatusEnum.TO_BE_PROCESSED);
                }
            } else {
                //驳回
                jgEquipTransfer.setPromoter("");
                jgEquipTransfer.setApplyStatus(String.valueOf(FlowStatusEnum.REJECTED.getCode()));
                jgEquipTransfer.setSupervisoryCode(jgEquipTransferDto.getSupervisoryCode());
                jgEquipTransfer.setEquList(jgEquipTransferDto.getEquList());
                jgEquipTransfer.setNextTaskId(workflowResultDto.getNextTaskId());
                jgEquipTransfer.setNextExecuteUserIds(workflowResultDto.getNextExecutorUserIds());
                //jgEquipTransfer.setInstanceId(workflowResultDto.getInstanceId());
                // 上个代办改为驳回
                taskV2Model = this.updateLastTodo(jgEquipTransfer, FlowStatusEnum.REJECTED);
                this.createNewTodo(jgEquipTransfer, workflowResultDto, taskV2Model, FlowStatusEnum.REJECTED);
            }
            updateById(jgEquipTransfer);
            commonService.saveExecuteFlowData2Redis(instanceId, this.buildInstanceRuntimeData(jgEquipTransfer));
            this.delRepeatUseEquipData(jgEquipTransfer.getSequenceNbr(), jgEquipTransfer.getApplyStatus(), jgEquipTransfer.getUseUnitCreditCode());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    public InstanceRuntimeData buildInstanceRuntimeData(JgEquipTransfer jgEquipTransfer) {
        return InstanceRuntimeData.builder()
                .nextExecuteUserIds(jgEquipTransfer.getNextExecuteUserIds())
                .promoter(jgEquipTransfer.getPromoter())
                .nextTaskId(jgEquipTransfer.getNextTaskId())
                .build();
    }

    /**
     * 撤回操作
     *
     * @param equipTransferInfo 设备移交信息
     */
    @Transactional(rollbackFor = Exception.class)
    public void cancel(JgEquipTransferDto equipTransferInfo) {
        String instanceId = equipTransferInfo.getInstanceId();
        String nextTaskId = equipTransferInfo.getNextTaskId();
        String lockKey = CommonServiceImpl.buildJgExecuteLockKey(instanceId);
        RLock lock = redissonClient.getLock(lockKey);
        try {
            boolean isLocked = lock.tryLock(0, 180, TimeUnit.SECONDS);
            // 解决并发问题：多个人同时操作一个流程（并发执行通过、驳回、撤回）
            if (!isLocked) {
                throw new BadRequest("当前流程已经被执行！请重新打开页面查看并执行！");
            }
            // 流程执行时，状态及权限校验
            commonService.checkForRevocationFlow(nextTaskId, instanceId);
            // 查询装备移交信息
            JgEquipTransfer equipTransfer = baseMapper.selectById(equipTransferInfo.getSequenceNbr());

            // 回滚工作流
            ProcessTaskDTO processTaskDTO = cmWorkflowService.rollBack(equipTransferInfo.getInstanceId());
            WorkflowResultDto workflowResultDto = commonService.buildWorkFlowInfo(Collections.singletonList(processTaskDTO)).get(0);
            equipTransfer.setPromoter("");
            equipTransfer.setNextExecuteIds(workflowResultDto.getNextExecutorRoleIds());
            equipTransfer.setNextExecuteUserIds(workflowResultDto.getNextExecutorUserIds());
            equipTransfer.setApplyStatus(String.valueOf(FlowStatusEnum.ROLLBACK.getCode()));
            equipTransfer.setNextTaskId(workflowResultDto.getNextTaskId());
            baseMapper.updateById(equipTransfer);
            JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(equipTransfer));
            jsonObject.put("nextExecuteUser", equipTransfer.getNextExecuteIds());
            jsonObject.put("taskType", BusinessTypeEnum.JG_EQUIPMENT_HANDOVER.getCode());
            jsonObject.put("flowStatus", FlowStatusEnum.ROLLBACK.getCode());
            jsonObject.put("flowStatusLabel", FlowStatusEnum.ROLLBACK.getName());
            commonService.rollbackTask(equipTransfer.getInstanceId(), jsonObject);
            commonService.saveExecuteFlowData2Redis(instanceId, this.buildInstanceRuntimeData(equipTransfer));
            this.delRepeatUseEquipData(equipTransfer.getSequenceNbr(), equipTransfer.getApplyStatus(), equipTransfer.getUseUnitCreditCode());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    private String getStringFromMap(Map<String, Object> map, String key) {
        return map.getOrDefault(key, "").toString();
    }

    @Override
    public Page<JgEquipTransferDto> queryForJgEquipTransferPage(Page<JgEquipTransferDto> page, String sort, JgEquipTransferDto dto, ReginParams reginParams) {
        CompanyBo company = reginParams.getCompany();
        Map<String, Object> companyTypeMap = jrmInstallationNoticeService.getCompanyType();
        String companyLevel = getStringFromMap(companyTypeMap, "companyLevel");
        String companyType = getStringFromMap(companyTypeMap, "companyType");
        if ("company".equals(companyLevel) && companyType != null) {
            if (companyType.contains(CompanyTypeEnum.USE.getCode()) || companyType.contains(CompanyTypeEnum.INDIVIDUAL.getCode())) {
                dto.setUseUnitCodeFilter(company.getCompanyCode().contains("_") ? company.getCompanyCode().split("_")[1] : company.getCompanyCode());
            }
            if (companyType.contains(CompanyTypeEnum.CONSTRUCTION.getCode())) {
                dto.setInstallUnitCodeFilter(company.getCompanyCode());
            }
        }
        SortVo sortMap = commonService.sortFieldConversion(sort);
        Page<JgEquipTransferDto> equipTransferPage = this.baseMapper.queryForPage(page, sortMap, dto, reginParams.getUserModel().getUserId());
        equipTransferPage.getRecords().forEach(transfer -> {
            if (Objects.nonNull(transfer.getApplyStatus())) {
                transfer.setApplyStatusDesc(FlowStatusEnum.getNameByType(Long.valueOf(transfer.getApplyStatus())));
            }
        });
        return equipTransferPage;
    }

    /**
     * 列表查询-导出用
     */
    public List<EquipTransferVo> queryTransferInIds(List<String> ids) {
        List<EquipTransferVo> equipTransferVos = this.baseMapper.queryEquipTransferInIds(ids);
        return equipTransferVos.stream()
                .peek(transfer -> {
                    if (Objects.nonNull(transfer.getApplyStatus())) {
                        transfer.setApplyStatus(FlowStatusEnum.getNameByType(Long.parseLong(transfer.getApplyStatus())));
                    }
                })
                .collect(Collectors.toList());
    }


    @Override
    public Map<String, Object> queryBySequenceNbr(Long sequenceNbr) {
        JgEquipTransfer equipTransfer = baseMapper.selectById(sequenceNbr);
        if (Objects.isNull(equipTransfer)) {
            return null;
        }
        this.doCompensate(equipTransfer);
        Map<String, Object> equipTransferInfo = createEquipTransferInfo(equipTransfer);
        if (FlowStatusEnum.TO_BE_FINISHED.getCode() == Integer.parseInt(equipTransfer.getApplyStatus())) {
            // 已完成状态显示历史数据
            // 1.设备历史信息
            JSONObject his = commonService.queryHistoryData(sequenceNbr);
            // 兼容老数据
            if (his == null) {
                // 1.设备信息
                Map<String, Object> equipMap = getEquipInfonNew(sequenceNbr);
                // 2.移交业务字段信息
                equipMap.putAll(equipTransferInfo);
                return equipMap;
            } else {
                // 2.移交业务字段信息
                CommonServiceImpl.formatTime2StrDateForEquip(his);
                his.putAll(equipTransferInfo);
                return his;
            }
        } else {
            Map<String, Object> equipMap = getEquipInfonNew(sequenceNbr);
            return Stream.concat(equipTransferInfo.entrySet().stream(),
                            equipMap.entrySet().stream())
                    .filter(entry -> entry.getValue() != null)
                    .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (existing, replacement) -> existing));
        }

    }

    private Map<String, Object> getEquipInfonNew(Long sequenceNbr) {
        List<Map<String, Object>> equipmentInfos = this.baseMapper.queryEquipInformation(sequenceNbr);
        Map<String, Object> equipMap = null;
        if (equipmentInfos != null && !equipmentInfos.isEmpty()) {
            String equId = (String) equipmentInfos.get(0).get("equId");
            if (equId != null) {
                equipMap = idxBizJgRegisterInfoService.getDetailFieldCamelCaseByRecord(equId);
            }
        }
        return equipMap;
    }

    /**
     * 插入代办
     */
    private void buildTask(List<JgEquipTransfer> list, List<WorkflowResultDto> workflowResultList) {
        if (CollectionUtils.isEmpty(list) || CollectionUtils.isEmpty(workflowResultList)) {
            return;
        }
        List<TaskModelDto> taskModelList = new ArrayList<>();
        IntStream.range(0, list.size()).forEach(index -> {
            TaskModelDto taskModelDto = this.buildTaskModelDto(list.get(index), workflowResultList.get(index));
            taskModelList.add(taskModelDto);
        });
        commonService.buildTaskModel(taskModelList);
    }

    /**
     * 启动工作流
     *
     * @param submitType 提交类型
     * @param deviceList 设备列表
     * @return 工作流信息
     */
    private List<WorkflowResultDto> startWorkFlow(String receiveOrgCode, String submitType, List<Map<String, Object>> deviceList) {
        if (!SUBMIT_TYPE_FLOW.equals(submitType)) {
            return new ArrayList<>();
        }
        ActWorkflowBatchDTO actWorkflowBatchDTO = new ActWorkflowBatchDTO();
        List<ActWorkflowStartDTO> list = deviceList.stream()
                .map(item -> {
                    ActWorkflowStartDTO dto = new ActWorkflowStartDTO();
                    dto.setProcessDefinitionKey(EQUIP_TRANSFER_PROCESS_KEY);
                    dto.setBusinessKey(item.get("SEQUENCE_NBR").toString());
                    dto.setCompleteFirstTask(Boolean.TRUE);
                    dto.setNextExecuteUserCompanyCode(receiveOrgCode);
                    return dto;
                })
                .collect(Collectors.toList());

        actWorkflowBatchDTO.setProcess(list);
        List<ProcessTaskDTO> processTaskDTOS = cmWorkflowService.startBatch(actWorkflowBatchDTO);
        // 组装工作流返回的数据
        return commonService.buildWorkFlowInfo(processTaskDTOS);
    }

    /**
     * 字段拼接
     *
     * @param model 设备信息
     */
    private void convertField(JgEquipTransferDto model) {
        if (null == model) {
            return;
        }
        String installUnitId = model.getInstallUnitCreditCode();
        if (!ObjectUtils.isEmpty(installUnitId)) {
            String[] installUnitIdList = installUnitId.split("_");
            if (installUnitIdList.length > 1) {
                model.setInstallUnitCreditCode(installUnitIdList[0]);
                model.setInstallUnitName(installUnitIdList[1]);
            }
        }
    }

    private JgEquipTransferEq buildJgEquipTransferEq(Map<String, Object> obj, String applyNo) {
        JgEquipTransferEq jgEquipTransferEq = new JgEquipTransferEq();
        jgEquipTransferEq.setEquId(String.valueOf(obj.get("SEQUENCE_NBR")));
        jgEquipTransferEq.setEquipTransferId(applyNo);
        return jgEquipTransferEq;
    }

    private JgEquipTransfer buildJgEquipTransfer(JgEquipTransferDto model, String applyNo, ReginParams reginParams,
                                                 String submitType, List<WorkflowResultDto> workflowResultList, int i) {
        JgEquipTransfer dto = new JgEquipTransfer();
        BeanUtils.copyProperties(model, dto);
        dto.setApplyNo(applyNo);
        dto.setApplyDate(new Date());
        dto.setCreateUserName(reginParams.getUserModel().getRealName());
        dto.setCreateUserId(reginParams.getUserModel().getUserId());
        dto.setCreateUserCompanyName(reginParams.getCompany().getCompanyName());

        if (SUBMIT_TYPE_FLOW.equals(submitType)) {
            WorkflowResultDto workflowResult = workflowResultList.get(i);
            dto.setNextExecuteIds(workflowResult.getNextExecutorRoleIds());
            dto.setInstanceStatus(workflowResult.getNextExecutorRoleIds() + "," + workflowResult.getExecutorRoleIds());
            dto.setPromoter(reginParams.getUserModel().getUserId());
            dto.setNextTaskId(workflowResult.getNextTaskId());
            dto.setNextExecuteUserIds(workflowResult.getNextExecutorUserIds());
        } else {
            dto.setNextExecuteUserIds(RequestContext.getExeUserId());
        }
        if (!CollectionUtils.isEmpty(workflowResultList)) {
            dto.setInstanceId(workflowResultList.get(i).getInstanceId());
            dto.setApplyStatus(String.valueOf(FlowStatusEnum.TO_BE_PROCESSED.getCode()));
        } else {
            dto.setApplyStatus(String.valueOf(FlowStatusEnum.TO_BE_SUBMITTED.getCode()));
        }
        return dto;
    }

    private List<JgEquipTransferEq> buildJgEquipTransferEqList(List<JgEquipTransferEq> equipTransferEqList, List<JgEquipTransfer> list) {
        return equipTransferEqList.stream()
                .map(transferEq -> {
                    Long sequenceNbr = list.stream()
                            .filter(transfer -> transferEq.getEquipTransferId().equals(transfer.getApplyNo()))
                            .findFirst()
                            .map(JgEquipTransfer::getSequenceNbr)
                            .orElse(null);
                    return transferEq.setEquipTransferId(String.valueOf(sequenceNbr));
                })
                .collect(Collectors.toList());
    }

    private void handleResponseModel(ResponseModel<List<String>> listResponseModel, String errorMessagePrefix) {
        if (listResponseModel == null || listResponseModel.getStatus() != HttpStatus.OK.value()) {
            log.error(errorMessagePrefix + "{}", listResponseModel != null ? listResponseModel.getMessage() : "null");
            throw new BadRequest("告知单生成失败！");
        }
    }

    private void handleApplyNoList(List<String> applyNoList) {
        if (CollectionUtils.isEmpty(applyNoList)) {
            log.error("告知单返回为空");
            throw new BadRequest("告知单生成失败！");
        }
    }

    private Map<String, Object> createEquipTransferInfo(JgEquipTransfer equipTransfer) {
        Map<String, Object> equipTransferInfo = new HashMap<>(BeanUtil.beanToMap(equipTransfer, false, true));
        equipTransferInfo.put("installUnitCreditCode", equipTransfer.getInstallUnitCreditCode() + "_" + equipTransfer.getInstallUnitName());
        return equipTransferInfo;
    }

    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteForBatch(Long[] ids) {
        Collection<JgEquipTransfer> jgEquipTransfers = this.listByIds(Arrays.asList(ids));
        for (JgEquipTransfer notice : jgEquipTransfers) {
            // 删除代办 + 中止流程
            commonService.deleteTaskModel(String.valueOf(notice.getSequenceNbr()), notice.getInstanceId());
            // 删除单子
            this.baseMapper.deleteById(notice.getSequenceNbr());
            // 删除对应eq
            jgEquipTransferEqMapper.delete(new LambdaQueryWrapper<JgEquipTransferEq>()
                    .eq(JgEquipTransferEq::getEquipTransferId, notice.getSequenceNbr()));
            // 删除单子对应历史表数据
            jgRegistrationHistoryMapper.delete(new LambdaQueryWrapper<JgRegistrationHistory>()
                    .eq(JgRegistrationHistory::getCurrentDocumentId, notice.getSequenceNbr()));
        }
        return Boolean.TRUE;
    }

    @Override
    public boolean beforeCheck(JgEquipTransfer jgEquipTransfer) {
        return jgEquipTransfer.getInstanceId() != null && !jgEquipTransfer.getApplyStatus().equals(String.valueOf(FlowStatusEnum.TO_BE_FINISHED.getCode())) &&!jgEquipTransfer.getApplyStatus().equals(String.valueOf(FlowStatusEnum.TO_BE_DISCARD.getCode()));
    }

    @Override
    public void compensate(JgEquipTransfer jgEquipTransfer) {
        commonService.saveExecuteFlowData2Redis(jgEquipTransfer.getInstanceId(), this.buildInstanceRuntimeData(jgEquipTransfer));
    }

}