package com.friday.distributor.service;

import com.alibaba.dubbo.common.utils.CollectionUtils;
import com.alibaba.fastjson.JSON;
import com.friday.base.common.annotation.MethodLog;
import com.friday.distributor.constant.States;
import com.friday.distributor.mapper.JobExecuteLogMapper;
import com.friday.distributor.mapper.JobInvokeMapper;
import com.friday.distributor.po.JobExecuteLogPo;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.friday.base.common.response.DubboResult;
import com.friday.distributor.common.ExecutorMethodInvokeHelper;
import com.friday.distributor.mapper.TaskInvokeMapper;
import com.friday.distributor.po.JobInvoke;
import com.friday.distributor.po.TaskInvoke;
import com.friday.operation.api.distributor.dto.*;
import com.friday.operation.api.distributor.service.IDistributorOperationService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Service
@Slf4j
public class DistributorOperationService implements IDistributorOperationService {
    @Autowired
    private JobInvokeMapper jobInvokeMapper;
    @Autowired
    private TaskInvokeMapper taskInvokeMapper;
    @Autowired
    private ExecutorMethodInvokeHelper executorInvoker;
    @Autowired
    private JobExecuteLogMapper jobExecuteLogMapper;

    @Override
    public DubboResult<TaieTaskRecordPageResult> queryTaskRecordByPage(TaieTaskRecordFilter filter) {
        log.info("开始分页查询任务执行记录:{}", JSON.toJSONString(filter));
        try {
            if (filter.getPage() * filter.getPageSize() != 0) {
                PageHelper.startPage(filter.getPage(), filter.getPageSize());
            }
            Page<TaieTaskRecord> recordPage = jobInvokeMapper.selectTaskRecordByPage(filter);
            List<TaieTaskRecord> records = recordPage.getResult();
            records.forEach(r -> {
                List<JobInvoke> invokes = jobInvokeMapper.selectJobByTaskId(r.getTaskId());
                List<String> execRobots = invokes.stream().filter(i -> StringUtils.isNotEmpty(i.getExecTaieRobot())).map(JobInvoke::getExecTaieRobot).collect(Collectors.toList());
                r.setExecRobot(String.join("/", execRobots));
                List<String> failMsg = invokes.stream().filter(i -> StringUtils.isNotEmpty(i.getFailMsg())).map(JobInvoke::getFailMsg).collect(Collectors.toList());
                r.setFailMsg(String.join("/", failMsg));
                TaskInvoke taskInvoke = taskInvokeMapper.selectTaskByTaskId(r.getTaskId());
                r.setStartTime(taskInvoke.getCreateTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
                if(States.TaskState.EXECUTED.name().equals(taskInvoke.getTaskState())){
                    r.setEndTime(taskInvoke.getUpdateTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
                }
                TaskResultFilter resultFilter = new TaskResultFilter();
                resultFilter.setTaskId(r.getTaskId());
                DubboResult<TaskResultDto> result = executorInvoker.getTaskResult(resultFilter);
                if(Objects.nonNull(result) && result.success()){
                    r.setResultFiles(result.getObject().getFiles());
                }
            });
            TaieTaskRecordPageResult recordPageResult = TaieTaskRecordPageResult.builder()
                    .records(records)
                    .page(recordPage.getPageNum())
                    .pageSize(recordPage.getPageSize())
                    .totalPage(recordPage.getPages())
                    .totalPageSize(recordPage.getTotal())
                    .build();
            return DubboResult.newSuccess(recordPageResult);
        } catch (Exception e){
            log.error("分页查询任务执行记录失败", e);
            return DubboResult.newFailure(DubboResult.SERVER_EXCEPTION, "分页查询任务执行记录失败");
        }
    }

    @Override
    public DubboResult<ArrayList<TaieJobRecord>> queryTaskExecDetailByTaskId(String taskId) {
        if (StringUtils.isEmpty(taskId)) {
            return DubboResult.newFailure(DubboResult.CLIENT_EXCEPTION, "无效入参");
        }
        try {
            List<JobInvoke> invokes = jobInvokeMapper.selectJobByTaskId(taskId);
            if (CollectionUtils.isEmpty(invokes)) {
                return DubboResult.newFailure(DubboResult.SERVER_EXCEPTION, "未查询到对应子任务记录列表");
            }
            ArrayList<TaieJobRecord> result = (ArrayList<TaieJobRecord>) invokes.stream().map(i -> TaieJobRecord.builder()
                    .invokeId(i.getId())
                    .state(i.getJobState())
                    .execRobot(i.getExecTaieRobot())
                    .failMsg(i.getFailMsg())
                    .startTime(Objects.isNull(i.getStartTime()) ? null : i.getStartTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")))
                    .endTime(Objects.isNull(i.getEndTime()) ? null : i.getEndTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")))
                    .build()).collect(Collectors.toList());
            return DubboResult.newSuccess(result);
        } catch (Exception e) {
            log.error("查询任务执行详情失败", e);
            return DubboResult.newFailure(DubboResult.SERVER_EXCEPTION, "查询任务执行详情失败");
        }
    }

	@Override
	@MethodLog(desc="同步job执行记录")
	public DubboResult syncJobLog(JobExecuteLogDto executeLog) {
		try {
			TaskInvoke taskPo = taskInvokeMapper.selectTaskByTaskId(executeLog.getTaskId());
			if(taskPo == null) {
				return DubboResult.newFailure(DubboResult.SERVER_EXCEPTION, "任务不存在");
			}
			JobInvoke jobPo = jobInvokeMapper.selectJobById(executeLog.getInvokeId());
			if(jobPo == null) {
				return DubboResult.newFailure(DubboResult.SERVER_EXCEPTION, "任务不存在");
			}
			JobExecuteLogPo po = new JobExecuteLogPo(executeLog);
			Date now = new Date();
			po.setCreateTime(now);
			po.setUpdateTime(now);
			jobExecuteLogMapper.insertSelective(po);
			return DubboResult.newSuccess();
		} catch (Exception e){
            log.error("同步job执行记录失败", e);
            return DubboResult.newFailure(DubboResult.SERVER_EXCEPTION, "同步job执行记录失败");
        }
	}

	@Override
	public DubboResult<ArrayList<JobExecuteLogDto>> queryJobExecDetailByInvokeId(Integer invokeId) {
		try {
			List<JobExecuteLogPo> logList = jobExecuteLogMapper.selectByInvokeId(invokeId);
			ArrayList<JobExecuteLogDto> result = logList.stream().map(JobExecuteLogPo::createDto).collect(Collectors.toCollection(ArrayList::new));
			return DubboResult.newSuccess(result);
		} catch (Exception e){
            log.error("查询job日志记录失败", e);
            return DubboResult.newFailure(DubboResult.SERVER_EXCEPTION, "查询job日志记录失败");
        }
	}

	@Override
	public DubboResult<ArrayList<String>> queryJobModuleByInvokeId(Integer invokeId) {
		try {
			List<String> moduleList = jobExecuteLogMapper.selectModuleByInvokeId(invokeId);
			return DubboResult.newSuccess((ArrayList<String>)moduleList);
		} catch (Exception e){
            log.error("查询job日志记录失败", e);
            return DubboResult.newFailure(DubboResult.SERVER_EXCEPTION, "查询job日志记录失败");
        }
	}
}
