package com.friday.distributor.service;

import com.alibaba.dubbo.common.utils.CollectionUtils;
import com.alibaba.fastjson.JSON;
import com.friday.distributor.constant.States;
import com.friday.distributor.exception.DistributorRuntimeException;
import com.friday.base.common.response.DubboResult;
import com.friday.distributor.bean.Job;
import com.friday.distributor.bean.Task;
import com.friday.distributor.common.ExecDataService;
import com.friday.distributor.common.ExecutorMethodInvokeHelper;
import com.friday.distributor.mapper.QueueMapper;
import com.friday.distributor.po.JobInvoke;
import com.friday.distributor.po.QueuePo;
import com.friday.distributor.po.TaskInvoke;
import com.friday.distributor.queue.TaskFactory;
import com.friday.distributor.queue.TaskPersistHelper;
import com.friday.distributor.queue.TaskQueueManager;
import com.friday.operation.api.distributor.bean.BaseJob;
import com.friday.operation.api.distributor.dto.*;
import com.friday.operation.api.distributor.service.IDistributorService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.util.StringUtils;

import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @Description 任务分发主框架服务
 */
@Slf4j
@Service
public class DistributorService implements IDistributorService {
    @Autowired
    private TaskFactory taskFactory;
    @Autowired
    private DistributorExecuteService executeService;
    @Autowired
    private TaskQueueManager taskQueueManager;
    @Autowired
    private TaskPersistHelper taskPersistHelper;
    @Autowired
    private QueueMapper queueMapper;
    @Autowired
    private ExecutorMethodInvokeHelper executorInvoker;
    @Autowired
    private ExecDataService execDataService;

    @Override
    @Transactional
    public DubboResult<TaskStartResult> startTask(StartTaskReq startReq) {
        log.info("任务分发开始启动任务：" + JSON.toJSONString(startReq));
        Task task = null;
        try {
            DubboResult checkParamResult = executorInvoker.checkParam(startReq);
            if(!checkParamResult.success()){
                return checkParamResult;
            }
            task = taskFactory.initTask(startReq);
            List<BaseJob> baseJobs = executorInvoker.createJobs(task).getObject();
            String taskState = baseJobs.isEmpty() ? States.TaskState.NO_JOB_REQUIRED.name() : States.TaskState.UNEXECUTED.name();
            task.setState(taskState);
            taskPersistHelper.insertOrUpdateTaskRecord(task);
            if (baseJobs.isEmpty()) {
                return DubboResult.newFailure(DubboResult.SERVER_EXCEPTION, "本次启动没有需要执行的子任务");
            }
            List<Job> jobs = taskFactory.initJobs(task, baseJobs);
            for(Job job : jobs){
                taskPersistHelper.insertOrUpdateJobRecord(job);
                job.getJobInput().getBaseParam().setInvokeId(job.getInvokeId());
            }
            task.setJobs(jobs);
            TaskStartResult result = task.syncStart() ? executeService.syncStartTaieTask(task)  : executeService.asyncStartTaieTask(task);
            return DubboResult.newSuccess(result);
        } catch (DistributorRuntimeException e){
            return DubboResult.newFailure(DubboResult.SERVER_EXCEPTION, e.getMessage());
        } catch (Exception e){
            log.error("启动任务失败，任务详情：" + JSON.toJSONString(startReq), e);
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return DubboResult.newFailure(DubboResult.SERVER_EXCEPTION, "启动任务失败:" + e.getMessage());
        } finally {
            if(Objects.nonNull(task) && !taskPersisted(task)){
                taskQueueManager.removeTask(task, task.getQueueKey());
            }
        }
    }

    private boolean taskPersisted(Task task){
        if(StringUtils.isEmpty(task.getTaskId())){
            return false;
        }
        return Objects.nonNull(taskPersistHelper.getTaskInvokeByTaskId(task.getTaskId()));
    }

    //开始全局队列轮询
//    @Scheduled(cron = "0/30 * * * * ?")
    public void startQueuePolling(){
        List<QueuePo> allQueues = queueMapper.selectAllQueues();
        allQueues.forEach(queue -> taskQueueManager.queuePolling(queue.getKey()));
    }



    @Override
    public DubboResult<TaskStartResult> restartTask(RestartTaskReq restartReq) {
        if(StringUtils.isEmpty(restartReq.getTaskId())){
            return DubboResult.newFailure(DubboResult.CLIENT_EXCEPTION, "无效的taskId");
        }
        try {
            TaskInvoke invoke = taskPersistHelper.getTaskInvokeByTaskId(restartReq.getTaskId());
            StartTaskReq startReq = JSON.parseObject(invoke.getTaskInput(), StartTaskReq.class);
            return this.startTask(startReq);
        } catch (Exception e){
            log.error("重启任务失败:taskId={}", restartReq.getTaskId(), e);
            return DubboResult.newFailure(DubboResult.SERVER_EXCEPTION, "重启任务失败");
        }
    }

    @Override
    public DubboResult stopTask(StopTaskReq stopReq) {
        if(CollectionUtils.isEmpty(stopReq.getTasks())){
            return DubboResult.newFailure(DubboResult.CLIENT_EXCEPTION, "无效的task标识");
        }
        try {
            for(TaskIdentifier identifier : stopReq.getTasks()){
                if(StringUtils.isEmpty(identifier.getTaskId())){
                    return DubboResult.newFailure(DubboResult.CLIENT_EXCEPTION, "无效的taskId");
                }
                if(CollectionUtils.isEmpty(identifier.getInvokeIds())){
                    List<Integer> jobInvokeIds = taskPersistHelper.getJobsByTaskId(identifier.getTaskId()).stream().map(JobInvoke::getId).collect(Collectors.toList());
                    identifier.setInvokeIds(jobInvokeIds);
                }
                for(Integer invokeId : identifier.getInvokeIds()){
                    Optional<Job> job = taskQueueManager.getJobById(invokeId);
                    job.ifPresent(value -> executeService.stopTaieJob(value));
                }
            }
            return DubboResult.newSuccess();
        } catch (Exception e){
            log.error("停止任务失败", e);
            return DubboResult.newFailure(DubboResult.SERVER_EXCEPTION, "停止任务失败");
        }

    }

    @Override
    public DubboResult<TaskResultDto> getTaskResult(TaskResultFilter filter) {
        if(StringUtils.isEmpty(filter.getTaskId())){
            return DubboResult.newFailure(DubboResult.CLIENT_EXCEPTION, "无效的taskId");
        }
        try {
            DubboResult<TaskResultDto> result = executorInvoker.getTaskResult(filter);
            if(Objects.isNull(result) || !result.success()){
                return result;
            }
            if(Objects.isNull(result.getObject())){
                return DubboResult.newSuccess(new TaskResultDto());
            }
            TaskResultDto resultDto = result.getObject();
            TaskResultStateDto execState = execDataService.getTaskState(filter.getTaskId());
            resultDto.setExecState(execState.getExecState());
            resultDto.setFailMag(execState.getFailMag());
            return DubboResult.newSuccess(resultDto);
        } catch (Exception e){
            log.error("获取执行结果失败:taskId={}", filter.getTaskId(), e);
            return DubboResult.newFailure(DubboResult.SERVER_EXCEPTION, "获取执行结果失败");
        }
    }

    @Override
    public DubboResult getData(DataRequest dataReq) {
        return executorInvoker.getData(dataReq);
    }

    @Override
    public DubboResult syncData(DataRequest dataReq) {
        return executorInvoker.syncData(dataReq);
    }

    @Override
    public DubboResult handleFile(HandleFileDto handleFile) {
        return executorInvoker.handleFile(handleFile);
    }
}
