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

import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.stylefeng.roses.kernel.dsctn.api.context.DataSourceContext;
import cn.stylefeng.roses.kernel.rule.enums.DbTypeEnum;
import cn.stylefeng.workflow.api.entity.task.RuTask;
import cn.stylefeng.workflow.api.enums.TaskEventTypeEnum;
import cn.stylefeng.workflow.api.enums.TaskStatusEnum;
import cn.stylefeng.workflow.api.pojo.InstanceContext;
import cn.stylefeng.workflow.event.api.EventPublishApi;
import cn.stylefeng.workflow.instance.api.WorkflowStatusApi;
import cn.stylefeng.workflow.instance.modular.task.mapper.RuTaskMapper;
import cn.stylefeng.workflow.instance.modular.task.service.TaskDaoWithEvent;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class TaskDaoWithEventImpl implements TaskDaoWithEvent {

    @Resource
    private RuTaskMapper ruTaskMapper;

    @Resource
    private EventPublishApi eventPublishApi;

    @Resource
    private WorkflowStatusApi workflowStatusApi;

    @Override
    public void batchSaveTaskList(List<RuTask> ruTaskList) {

        RuTask ruTask = ruTaskList.get(0);
        InstanceContext instanceContext = workflowStatusApi.buildInstanceContext(ruTask.getInstanceId());

        this.batchSaveTaskList(ruTaskList, instanceContext);
    }

    @Override
    public void batchSaveTaskList(List<RuTask> ruTaskList, InstanceContext instanceContext) {
        if (ObjectUtil.isEmpty(ruTaskList)) {
            return;
        }

        if (DbTypeEnum.MYSQL.equals(DataSourceContext.me().getCurrentDbType())) {
            this.ruTaskMapper.insertBatchSomeColumn(ruTaskList);
        } else {
            for (RuTask ruTask : ruTaskList) {
                ruTaskMapper.insert(ruTask);
            }
        }

        eventPublishApi.publishModelTaskEvent(TaskEventTypeEnum.SAVE_TASK, ruTaskList, instanceContext);
    }

    @Override
    public void saveTask(RuTask ruTask) {

        InstanceContext instanceContext = workflowStatusApi.buildInstanceContext(ruTask.getInstanceId());
        this.saveTask(ruTask, instanceContext);
    }

    @Override
    public void saveTask(RuTask ruTask, InstanceContext instanceContext) {
        if (ObjectUtil.isEmpty(ruTask)) {
            return;
        }
        this.ruTaskMapper.insert(ruTask);

        eventPublishApi.publishModelTaskEvent(TaskEventTypeEnum.SAVE_TASK, ListUtil.list(true, ruTask), instanceContext);
    }

    @Override
    public void updateTaskStatus(RuTask ruTask, Integer taskStatus) {

        ruTask.setTaskStatus(taskStatus);

        this.updateTaskByTaskId(ruTask);
    }

    @Override
    public void updateTaskStatus(RuTask ruTask, Integer taskStatus, String suggestContent) {

        ruTask.setTaskStatus(taskStatus);

        ruTask.setSuggestContent(suggestContent);

        if (ObjectUtil.isNotEmpty(suggestContent)) {
            ruTask.setSuggestTime(new Date());
        }

        if (ruTask.getBeginTime() == null && TaskStatusEnum.PROCESSING.getCode().equals(taskStatus)) {
            ruTask.setBeginTime(new Date());
        }

        this.updateTaskByTaskId(ruTask);
    }

    @Override
    public void updateReadFlag(RuTask ruTask, String readFlag) {
        ruTask.setReadFlag(readFlag);
        this.ruTaskMapper.updateById(ruTask);

        InstanceContext instanceContext = workflowStatusApi.buildInstanceContext(ruTask.getInstanceId());

        eventPublishApi.publishModelTaskEvent(TaskEventTypeEnum.SET_READ_FLAG, ListUtil.list(true, ruTask), instanceContext);
    }

    @Override
    public void removeTaskList(List<RuTask> taskList) {
        if (ObjectUtil.isEmpty(taskList)) {
            return;
        }

        RuTask tempTask = taskList.get(0);
        Long instanceId = tempTask.getInstanceId();

        List<Long> taskIdList = taskList.stream().map(RuTask::getTaskId).collect(Collectors.toList());
        this.ruTaskMapper.deleteBatchIds(taskIdList);

        InstanceContext instanceContext = workflowStatusApi.buildInstanceContext(instanceId);

        eventPublishApi.publishModelTaskEvent(TaskEventTypeEnum.DELETE_TASK, taskList, instanceContext);
    }

    private void updateTaskByTaskId(RuTask ruTask) {
        this.ruTaskMapper.updateById(ruTask);

        InstanceContext instanceContext = workflowStatusApi.buildInstanceContext(ruTask.getInstanceId());

        eventPublishApi.publishModelTaskEvent(TaskEventTypeEnum.UPDATE_TASK_STATUS, ListUtil.list(true, ruTask), instanceContext);
    }

}
