package com.yunzhupaas.flowable.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.dynamic.datasource.annotation.DSTransactional;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.ImmutableList;
import com.yunzhupaas.base.UserInfo;
import com.yunzhupaas.base.service.SuperServiceImpl;
import com.yunzhupaas.constant.MsgCode;
import com.yunzhupaas.exception.WorkFlowException;
import com.yunzhupaas.flowable.entity.*;
import com.yunzhupaas.flowable.enums.DivideRuleEnum;
import com.yunzhupaas.flowable.enums.NodeEnum;
import com.yunzhupaas.flowable.enums.TaskStatusEnum;
import com.yunzhupaas.flowable.mapper.TriggerTaskMapper;
import com.yunzhupaas.flowable.model.templatejson.TemplateJsonInfoVO;
import com.yunzhupaas.flowable.model.templatenode.ButtonModel;
import com.yunzhupaas.flowable.model.templatenode.TaskNodeModel;
import com.yunzhupaas.flowable.model.templatenode.nodejson.NodeModel;
import com.yunzhupaas.flowable.model.trigger.*;
import com.yunzhupaas.flowable.model.util.FlowNature;
import com.yunzhupaas.flowable.service.*;
import com.yunzhupaas.flowable.util.TriggerUtil;
import com.yunzhupaas.util.JsonUtil;
import com.yunzhupaas.util.StringUtil;
import com.yunzhupaas.util.UserProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 类的描述
 *
 * @author YUNZHUPAASYUNZHUPAAS开发组
 * @version 5.0.x
 * @since 2024/9/10 17:13
 */
@Service
public class TriggerTaskServiceImpl extends SuperServiceImpl<TriggerTaskMapper, TriggerTaskEntity>
        implements TriggerTaskService {
    @Autowired
    private TriggerRecordService triggerRecordService;
    @Autowired
    private TemplateService templateService;
    @Autowired
    private TemplateJsonService templateJsonService;
    @Autowired
    private TemplateNodeService templateNodeService;
    @Autowired
    private TriggerUtil triggerUtil;

    @Override
    public List<TriggerInfoListModel> getListByTaskId(String taskId, String nodeCode) {
        QueryWrapper<TriggerTaskEntity> queryWrapper = new QueryWrapper<>();
        if (StringUtil.isNotBlank(taskId)) {
            queryWrapper.lambda().eq(TriggerTaskEntity::getTaskId, taskId);
        }
        if (StringUtil.isNotBlank(nodeCode)) {
            queryWrapper.lambda().eq(TriggerTaskEntity::getNodeId, nodeCode);
        }
        queryWrapper.lambda().orderByDesc(TriggerTaskEntity::getStartTime);
        List<TriggerTaskEntity> list = this.list(queryWrapper);
        List<TriggerInfoListModel> modelList = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(list)) {
            for (TriggerTaskEntity triggerTask : list) {
                TriggerInfoListModel model = JsonUtil.getJsonToBean(triggerTask, TriggerInfoListModel.class);
                List<TriggerRecordEntity> recordList = triggerRecordService.getList(triggerTask.getId());
                model.setRecordList(recordList);
                modelList.add(model);
            }
        }
        return modelList;
    }

    @Override
    public boolean existTriggerTask(String taskId, String nodeId) {
        if (StringUtil.isBlank(taskId) || StringUtil.isBlank(nodeId)) {
            return false;
        }
        QueryWrapper<TriggerTaskEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(TriggerTaskEntity::getTaskId, taskId)
                .eq(TriggerTaskEntity::getNodeId, nodeId);
        return this.count(queryWrapper) > 0;
    }

    @Override
    public List<TriggerTaskEntity> getList(TriggerPagination pagination) {
        QueryWrapper<TriggerTaskEntity> queryWrapper = new QueryWrapper<>();
        if (StringUtil.isNotEmpty(pagination.getKeyword())) {
            queryWrapper.lambda().and(e -> e.like(TriggerTaskEntity::getFullName, pagination.getKeyword())
                    .or().like(TriggerTaskEntity::getId, pagination.getKeyword()));
        }
        if (ObjectUtil.isNotEmpty(pagination.getStartTime()) && ObjectUtil.isNotEmpty(pagination.getEndTime())) {
            queryWrapper.lambda().between(TriggerTaskEntity::getStartTime, new Date(pagination.getStartTime()),
                    new Date(pagination.getEndTime()));
        }
        queryWrapper.lambda().isNull(TriggerTaskEntity::getTaskId).orderByDesc(TriggerTaskEntity::getCreatorTime);
        Page<TriggerTaskEntity> page = new Page<>(pagination.getCurrentPage(), pagination.getPageSize());
        Page<TriggerTaskEntity> iPage = this.page(page, queryWrapper);
        return pagination.setData(iPage.getRecords(), page.getTotal());
    }

    @Override
    public TriggerInfoModel getInfo(String id) throws WorkFlowException {
        TriggerTaskEntity triggerTask = this.getById(id);
        if (null == triggerTask) {
            throw new WorkFlowException(MsgCode.FA001.get());
        }
        TriggerInfoModel model = new TriggerInfoModel();
        model.setTaskInfo(JsonUtil.getJsonToBean(triggerTask, TriggerTaskModel.class));
        TemplateJsonInfoVO jsonInfoVO = templateJsonService.getInfoVo(triggerTask.getFlowId());
        model.setFlowInfo(jsonInfoVO);
        List<TriggerRecordEntity> recordList = triggerRecordService.getList(triggerTask.getId());
        List<TaskNodeModel> nodeList = this.getNodeList(triggerTask, recordList);
        model.setNodeList(nodeList);
        recordList = recordList.stream().filter(e -> e.getStatus() != null).collect(Collectors.toList());
        model.setRecordList(recordList);
        ButtonModel btnInfo = model.getBtnInfo();
        if (ObjectUtil.equals(triggerTask.getStatus(), TaskStatusEnum.RUNNING.getCode())) {
            btnInfo.setHasCancelBtn(true);
        }
        return model;
    }

    public List<TaskNodeModel> getNodeList(TriggerTaskEntity triggerTask, List<TriggerRecordEntity> recordList) {
        List<TaskNodeModel> list = new ArrayList<>();
        if (ObjectUtil.equals(triggerTask.getStatus(), TaskStatusEnum.CANCEL.getCode())) {
            return list;
        }
        String flowId = triggerTask.getFlowId();
        List<TemplateNodeEntity> nodeEntityList = templateNodeService.getList(flowId);
        List<String> typeList = ImmutableList.of(NodeEnum.global.getType(), NodeEnum.connect.getType(), "confluence",
                "gateway");
        List<String> divideList = Arrays.stream(DivideRuleEnum.values()).map(DivideRuleEnum::getType)
                .collect(Collectors.toList());
        divideList.addAll(typeList);
        for (TemplateNodeEntity node : nodeEntityList) {
            if (divideList.contains(node.getNodeType())) {
                continue;
            }
            TaskNodeModel model = new TaskNodeModel();
            NodeModel nodeModel = JsonUtil.getJsonToBean(node.getNodeJson(), NodeModel.class);
            model.setNodeName(nodeModel.getNodeName());
            model.setNodeCode(nodeModel.getNodeId());
            model.setNodeType(nodeModel.getType());

            String type = null;
            String nodeCode = node.getNodeCode();
            if (ObjectUtil.equals(node.getNodeType(), NodeEnum.start.getType())) {
                nodeCode = FlowNature.START_CODE;
            } else if (ObjectUtil.equals(node.getNodeType(), NodeEnum.end.getType())) {
                nodeCode = FlowNature.END_CODE;
            }
            String finalNodeCode = nodeCode;
            TriggerRecordEntity record = recordList.stream()
                    .filter(e -> ObjectUtil.equals(e.getNodeCode(), finalNodeCode)).findFirst().orElse(null);
            if (null != record) {
                if (ObjectUtil.equals(record.getStatus(), 1)) {
                    type = "3";
                } else if (ObjectUtil.equals(record.getStatus(), 0)) {
                    type = "0";
                } else {
                    type = "1";
                }
            }
            model.setType(type);
            list.add(model);
        }
        return list;
    }

    @Override
    // @DSTransactional
    public void retry(String id) throws Exception {
        TriggerTaskEntity triggerTask = this.getById(id);
        if (null == triggerTask) {
            throw new WorkFlowException(MsgCode.FA001.get());
        }
        TemplateJsonEntity jsonEntity = templateJsonService.getInfo(triggerTask.getFlowId());
        TemplateEntity template = templateService.getInfo(jsonEntity.getTemplateId());
        if (!ObjectUtil.equals(template.getStatus(), 1)) {
            throw new WorkFlowException(MsgCode.WF146.get());
        }
        ExecuteModel model = new ExecuteModel();
        model.setFlowId(triggerTask.getFlowId());
        List<Map> jsonToList = JsonUtil.getJsonToList(triggerTask.getData(), Map.class);
        List<Map<String, Object>> dataList = triggerUtil.castListMap(jsonToList);
        model.setDataList(dataList);
        UserInfo userInfo = UserProvider.getUser();
        model.setUserInfo(userInfo);
        model.setParentId(triggerTask.getId());
        triggerUtil.execute(model);
    }

    @Override
    public void saveTriggerTask(TriggerTaskEntity entity) {
        this.save(entity);
    }

    @Override
    public void updateTriggerTask(TriggerTaskEntity entity) {
        this.updateById(entity);
    }

    @Override
    public void batchDelete(List<String> ids) {
        if (ids.isEmpty()) {
            return;
        }
        this.removeByIds(ids);
        triggerRecordService.delete(ids);
    }

    @Override
    public void deleteByTaskId(List<String> taskId) {
        if (CollectionUtil.isEmpty(taskId)) {
            return;
        }
        QueryWrapper<TriggerTaskEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().in(TriggerTaskEntity::getTaskId, taskId);
        List<TriggerTaskEntity> list = this.list(queryWrapper);
        if (CollectionUtil.isEmpty(list)) {
            return;
        }
        List<String> ids = list.stream().map(TriggerTaskEntity::getId).collect(Collectors.toList());
        this.setIgnoreLogicDelete().removeByIds(ids);
        this.clearIgnoreLogicDelete();
        QueryWrapper<TriggerRecordEntity> wrapper = new QueryWrapper<>();
        wrapper.lambda().in(TriggerRecordEntity::getTriggerId, ids);
        triggerRecordService.setIgnoreLogicDelete().remove(wrapper);
        triggerRecordService.clearIgnoreLogicDelete();
    }

    @Override
    public boolean checkByFlowIds(List<String> flowIds) {
        if (CollectionUtil.isNotEmpty(flowIds)) {
            QueryWrapper<TriggerTaskEntity> queryWrapper = new QueryWrapper<>();
            queryWrapper.lambda().in(TriggerTaskEntity::getFlowId, flowIds);
            return this.count(queryWrapper) > 0;
        }
        return false;
    }
}
