/**
 * 
 */
package org.springblade.etl.controller;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Stream;

import org.springblade.core.boot.ctrl.BladeController;
import org.springblade.core.log.annotation.ApiLog;
import org.springblade.core.mp.support.Condition;
import org.springblade.core.mp.support.Query;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.CollectionUtil;
import org.springblade.etl.dto.etl.JobGraph;
import org.springblade.etl.dto.etl.JobStatReq;
import org.springblade.etl.dto.etl.JobStatRes;
import org.springblade.etl.entity.Job;
import org.springblade.etl.entity.JobInstance;
import org.springblade.etl.enums.InstanceStatus;
import org.springblade.etl.service.JobInstanceService;
import org.springblade.etl.service.JobService;
import org.springblade.system.client.DataPermClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;

import cn.hutool.core.date.DateUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;

/**
 *	任务实例 操作处理
 *
 * @author aokunsang
 * @date   2023-07-28
 */
@RestController
@RequestMapping("/job-instance")
@Api(value = "任务实例相关接口", tags = "任务实例接口")
public class JobInstanceController extends BladeController {

	@Autowired
	private JobInstanceService jobInstanceService;
	
	@Autowired
	private JobService jobService;
	
	@Autowired
	private DataPermClient dataPermClient;
	
	/**
	 * 	列表数据
	 * @param jobInstance
	 * @return
	 */
	@GetMapping("/page")
	@ApiOperation(value = "分页查询任务实例", httpMethod = "GET")
	public R<IPage<JobInstance>> pageList(JobInstance jobInstance, Query query){
		Long userId = getUser().getUserId();
		LambdaQueryWrapper<JobInstance> queryWrapper = Condition.getQueryWrapper(jobInstance).lambda().orderByDesc(JobInstance::getId);
		if(jobInstance.getStartTime() != null && jobInstance.getEndTime() != null) {
			queryWrapper
			.gt(JobInstance::getCreateTime, DateUtil.format(jobInstance.getStartTime(), "yyyy-MM-dd"))
			.lt(JobInstance::getCreateTime, DateUtil.format(jobInstance.getEndTime(), "yyyy-MM-dd"));
		}
		Boolean checkSuperPermRet = dataPermClient.checkSuperPermission(getUser().getUserId());
		if(checkSuperPermRet == null || !checkSuperPermRet) {
			List<Integer> jobIdList = jobService.jobIdListOfPerm(userId);
			if(CollectionUtil.isEmpty(jobIdList)) {
				return R.data(new Page<JobInstance>());
			}
			queryWrapper.in(JobInstance::getJobId, jobIdList);
//			queryWrapper.inSql(JobInstance::getJobId, "select a.job_id from visual_data_permission a inner join data_permission_user b on a.data_perm_id = b.data_perm_id where b.user_id = " + userId);;
		}
		IPage<JobInstance> instancePage = jobInstanceService.page(Condition.getPage(query), queryWrapper);
		if(instancePage != null && CollectionUtil.isNotEmpty(instancePage.getRecords())) {
			instancePage.getRecords().forEach(item -> {
				Job job = jobService.getById(item.getJobId());
				item.setJobName(job == null ? "[已删除]" : job.getJobName());
			});
		}
		return R.data(instancePage);
	}
	
	/**
	 * 单条数据查询接口
	 * @param id
	 * @return
	 */
	@GetMapping("/info")
	@ApiOperation(value = "根据ID获取任务实例", httpMethod = "GET")
	public R<JobInstance> info(@RequestParam Integer id) {
		return R.data(jobInstanceService.getById(id));
	}
	
	/**
	 * 	删除数据接口
	 * @param id
	 * @return
	 */
	@ApiLog("ETL任务实例")
	@PostMapping("/delete")
	@ApiOperation(value = "根据ID删除任务实例", httpMethod = "POST")
	public R<String> doDelete(@RequestParam Integer id) {
		JobInstance dbJobInstance = jobInstanceService.getById(id);
		if(dbJobInstance.getInstanceStatus() == InstanceStatus.RUNNING) {
			return R.fail("实例运行中，不能删除");
		}
		return R.status(jobInstanceService.removeById(id));
	}
	
	/**
	 * 
	 * @param jobInstanceId
	 * @return
	 * @throws Exception 
	 */
	@ApiLog("ETL任务实例")
	@PostMapping("/cancel")
	@ApiOperation(value = "根据ID取消/暂停任务实例", httpMethod = "POST")
	public R<String> doCancel(Integer jobInstanceId) throws Exception {
		jobInstanceService.cancelJobInstance(jobInstanceId);
		return R.success("取消任务已提交，请关注状态变化");
	}
	
	/**
	 * 
	 * @param jobInstanceId
	 * @return
	 * @throws Exception
	 */
	@ApiLog("ETL任务实例")
	@PostMapping("/recover")
	@ApiOperation(value = "从最新的快照点恢复任务【断点续传】", httpMethod = "POST")
	public R<String> doRecover(Integer jobInstanceId) throws Exception {
		jobInstanceService.recoverJobInstance(jobInstanceId);
		return R.success("任务已重新提交，请关注状态变化");
	}
	
	/**
	 * 
	 * @param key
	 * @param jobGraph
	 * @return
	 * @throws Exception 
	 */
	@ApiLog("ETL任务实例")
	@PostMapping("/preview/{key}")
	@ApiOperation(value = "执行某个节点预览数据", httpMethod = "POST")
	@ApiImplicitParam(name = "key", required = true, paramType = "path", value = "key值自定义UUID随机字符串，与SINK_PREVIEW组件参数key保持一致")
	public R<List<JSONObject>> preview(@PathVariable String key, @RequestBody JobGraph jobGraph) throws Exception{
		return jobInstanceService.doPreview(key, jobGraph);
	}
	
	/**
	 * 
	 * @return
	 */
	@PostMapping("/stat")
	@ApiOperation(value = "任务运行状态的统计", httpMethod = "POST")
	public R<List<JobStatRes>> stat(@RequestBody JobStatReq jobStatReq){
		List<JobStatRes> resList = jobInstanceService.stat(jobStatReq);
		Map<InstanceStatus, JobStatRes> resMap = new HashMap<>();
		if(CollectionUtil.isNotEmpty(resList)) {
			resList.forEach(item -> resMap.put(InstanceStatus.of(item.getStatus()), item));
		}
		List<JobStatRes> dataList = new ArrayList<>(); 
		Stream.of(InstanceStatus.values()).forEach(item -> {
			JobStatRes jobStatRes = resMap.get(item);
			if(jobStatRes != null) {
				dataList.add(jobStatRes);
			}else {
				dataList.add(new JobStatRes(0L, item));
			}
		});
		return R.data(dataList);
	}
}