package org.springblade.flow.engine.controller;

import static org.springblade.flow.base.util.BpmnModelUtils.getAttributeValueByTaskDefinitionKey;
import static org.springblade.flow.base.util.BpmnModelUtils.getBpmnModelMainProcess;
import static org.springblade.flow.engine.custom.constants.GlobalProcessVariableConstants.BUSINESS_KEY;
import static org.springblade.flow.engine.custom.constants.GlobalProcessVariableConstants.BUSINESS_TITLE;
import static org.springblade.flow.engine.custom.constants.GlobalProcessVariableConstants.FORM_INFO_JSON;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.flowable.bpmn.model.FlowElement;
import org.flowable.bpmn.model.Process;
import org.flowable.engine.HistoryService;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.flowable.task.api.Task;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.springblade.flow.base.ActionResult;
import org.springblade.flow.base.util.ActivitiUtils;
import org.springblade.flow.base.util.FlowNature;
import org.springblade.flow.base.util.SpringContextHolder;
import org.springblade.flow.base.vo.PageListVO;
import org.springblade.flow.base.vo.PaginationVO;
import org.springblade.flow.engine.assembly.GlobalExPropertyDTO;
import org.springblade.flow.engine.assembly.UserTaskExPropertyDTO;
import org.springblade.flow.engine.custom.constants.GlobalProcessVariableConstants;
import org.springblade.flow.engine.custom.variables.entity.FormDataInfo;
import org.springblade.flow.engine.entity.FlowTaskEntity;
import org.springblade.flow.engine.entity.FlowTaskOperatorEntity;
import org.springblade.flow.engine.model.FlowHandleModel;
import org.springblade.flow.engine.model.flowbefore.FlowBeforeInfoVO;
import org.springblade.flow.engine.model.flowbefore.FlowBeforeListVO;
import org.springblade.flow.engine.model.flowengine.FlowModel;
import org.springblade.flow.engine.model.flowtask.PaginationFlowTask;
import org.springblade.flow.engine.service.FlowTaskNewService;
import org.springblade.flow.engine.service.FlowTaskOperatorService;
import org.springblade.flow.engine.service.FlowTaskService;
import org.springblade.flow.exception.WorkFlowException;
import org.springblade.flow.util.JsonUtil;
import org.springblade.flow.util.UserProvider;
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.RestController;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;

import cn.hutool.core.map.MapUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;

/**
 * 待我审核
 *
 * @author JNPF开发平台组
 * @version V3.1.0
 * @copyright 引迈信息技术有限公司
 * @date 2019年9月27日 上午9:18
 */
@Api(tags = "待我审核", value = "FlowBefore")
@RestController
@RequestMapping("/paas/workflow/Engine/FlowBefore")
public class FlowBeforeController {

	@Autowired
	private FlowTaskService flowTaskService;
	@Autowired
	private FlowTaskOperatorService flowTaskOperatorService;
	@Autowired
	private FlowTaskNewService flowTaskNewService;
	@Resource
	private TaskService taskService;
	@Resource
	private ActivitiUtils activitiUtils;
	@Resource
	private RuntimeService runtimeService;
	@Resource
	private UserProvider userProvider;
	@Resource
	private HistoryService historyService;

	/**
	 * 获取待我审核列表
	 *
	 * @param category           分类
	 * @param paginationFlowTask
	 * @return
	 */
	@ApiOperation("获取待我审核列表(有带分页)，1-待办事宜，2-已办事宜，3-抄送事宜")
	@GetMapping("/List/{category}")
	public ActionResult<PageListVO<FlowBeforeListVO>> list(@PathVariable("category") String category,
			PaginationFlowTask paginationFlowTask) {
		List<FlowTaskEntity> data = new ArrayList<>();
		if (FlowNature.WAIT.equals(category)) {
			data = flowTaskService.getWaitList(paginationFlowTask);
		} else if (FlowNature.TRIAL.equals(category)) {
			data = flowTaskService.getTrialList(paginationFlowTask);
		} else if (FlowNature.CIRCULATE.equals(category)) {
			data = flowTaskService.getCirculateList(paginationFlowTask);
		}
		List<FlowBeforeListVO> listVO = new LinkedList<>();
		if (data.size() > 0) {
			for (FlowTaskEntity taskEntity : data) {
				// 用户名称赋值
				FlowBeforeListVO vo = JsonUtil.getJsonToBean(taskEntity, FlowBeforeListVO.class);
				vo.setUserName(taskEntity.getCreatorUserName());
				vo.setFormType(Integer.valueOf(taskEntity.getFlowFormType()));
				listVO.add(vo);
			}
		}
		PaginationVO paginationVO = JsonUtil.getJsonToBean(paginationFlowTask, PaginationVO.class);
		return ActionResult.page(listVO, paginationVO);
	}

	/**
	 * 获取待我审批信息
	 *
	 * @param id 主键值
	 * @return
	 */
	@ApiOperation("获取待我审批信息")
	@GetMapping("/{id}")
	public ActionResult<FlowBeforeInfoVO> info(@PathVariable("id") String id, String taskNodeId)
			throws WorkFlowException {
		FlowBeforeInfoVO vo = flowTaskNewService.getBeforeInfo(id, taskNodeId);
		return ActionResult.success(vo);
	}

	/**
	 * 待我审核审核
	 *
	 * @param id              待办主键值
	 * @param flowHandleModel 流程经办
	 * @return
	 */
	@ApiOperation("待我审核审核")
	@PostMapping("/Audit/{id}")
	public ActionResult audit(@PathVariable("id") String id, @RequestBody FlowHandleModel flowHandleModel)
			throws WorkFlowException {
		try {
			Task task = taskService.createTaskQuery().taskId(id).includeProcessVariables().singleResult();
			if (task == null) {
				return ActionResult.fail("审核失败");

			} else {
				String taskID = task.getId();
				ProcessDefinitionEntity processDefinitionEntity = activitiUtils
						.getProcessDefinitionEntityById(task.getProcessDefinitionId());
				FlowTaskEntity flowTaskEntity = new FlowTaskEntity();
				RepositoryService repositoryService = SpringContextHolder.getBean(RepositoryService.class);
				Process process = getBpmnModelMainProcess(processDefinitionEntity.getId());
				String property = getAttributeValueByTaskDefinitionKey(process, "", "global");
				GlobalExPropertyDTO exPropertyDTO = JSONObject.parseObject(property,
						new TypeReference<GlobalExPropertyDTO>() {
						});

				String taskProperty = getAttributeValueByTaskDefinitionKey(process, task.getTaskDefinitionKey(),
						"userTask");
				UserTaskExPropertyDTO taskExPropertyDTO = JSONObject.parseObject(taskProperty.toString(),
						new TypeReference<UserTaskExPropertyDTO>() {
						});

				List<String> activeActivityIds = runtimeService.getActiveActivityIds(task.getProcessInstanceId());
				HashSet<String> setActiveActivityIds = new HashSet<>(activeActivityIds);
				Map<String, Object> processVariables = task.getProcessVariables();
				flowTaskEntity.setId(task.getFormKey());
				flowTaskEntity.setProcessId(task.getFormKey());
				flowTaskEntity.setEnCode(MapUtil.getStr(processVariables, GlobalProcessVariableConstants.BILL_CODE));
				flowTaskEntity.setFullName(MapUtil.getStr(processVariables, BUSINESS_TITLE));
				flowTaskEntity
						.setFlowUrgent(MapUtil.getInt(processVariables, GlobalProcessVariableConstants.FLOW_URGENT));
				flowTaskEntity
						.setFlowId(MapUtil.getStr(processVariables, GlobalProcessVariableConstants.FLOW_ENGINE_ID));
				flowTaskEntity.setFlowCode(processDefinitionEntity.getKey());
				flowTaskEntity.setFlowName(processDefinitionEntity.getName());
				flowTaskEntity.setFlowType(exPropertyDTO.getFlowType());
				flowTaskEntity.setFlowCategory(
						MapUtil.getStr(processVariables, GlobalProcessVariableConstants.PROCESS_CATEGORY));
				flowTaskEntity.setFlowForm(exPropertyDTO.getFormData());
				FormDataInfo formDataInfo = MapUtil.get(processVariables, FORM_INFO_JSON, FormDataInfo.class);
				flowTaskEntity.setFlowFormContentJson(formDataInfo.getFormDataJson());
				flowTaskEntity.setFlowTemplateJson(exPropertyDTO.getFlowTemplateJson());
				flowTaskEntity.setFlowVersion(exPropertyDTO.getFlowVersion());
				flowTaskEntity.setCreatorTime(task.getCreateTime());
				flowTaskEntity.setStartTime(task.getCreateTime());
				flowTaskEntity.setEndTime(null);
				flowTaskEntity
						.setStatus(MapUtil.getInt(processVariables, GlobalProcessVariableConstants.PROCESS_STATUS));

				flowTaskEntity.setCompletion(taskExPropertyDTO.getUserTaskBasicPropDTO().getProgress() == null ? 50
						: Integer.valueOf(taskExPropertyDTO.getUserTaskBasicPropDTO().getProgress()));
				flowTaskEntity.setEnabledMark(1);
				flowTaskEntity.setThisStepId(String.join(",", setActiveActivityIds));
				flowTaskEntity.setBusinessKey(MapUtil.getStr(processVariables, BUSINESS_KEY));
				flowTaskEntity.setFieldSet(exPropertyDTO.getFieldSet());
				flowTaskEntity.setUserTaskExPropertyDTO(taskExPropertyDTO);
				flowTaskEntity.setGlobalExPropertyDTO(exPropertyDTO);
				List<String> activityNames = new ArrayList<>();
				for (String setActiveActivityId : setActiveActivityIds) {
					FlowElement flowElement = process.getFlowElement(setActiveActivityId);
					activityNames.add(flowElement.getName());
				}
				flowTaskEntity.setThisStep(String.join(",", activityNames));
				LambdaQueryWrapper<FlowTaskOperatorEntity> lambdaQueryWrapper = new LambdaQueryWrapper();
				lambdaQueryWrapper.eq(FlowTaskOperatorEntity::getTaskNodeId, task.getId())
						.eq(FlowTaskOperatorEntity::getTaskId, task.getProcessInstanceId())
						.eq(FlowTaskOperatorEntity::getHandleId, userProvider.getUserId());
				List<FlowTaskOperatorEntity> list = flowTaskOperatorService.list(lambdaQueryWrapper);
				FlowModel flowModel = JsonUtil.getJsonToBean(flowHandleModel, FlowModel.class);
				flowTaskNewService.audit(flowTaskEntity, list.get(0), flowModel, task);
			}
			return ActionResult.success("审核成功");
		} catch (Exception e) {
			e.printStackTrace();
			return ActionResult.fail("审核失败");
		}
	}

	/**
	 * 待我审核驳回
	 *
	 * @param id              待办主键值
	 * @param flowHandleModel 经办信息
	 * @return
	 */
	@ApiOperation("待我审核驳回(拒绝按钮)")
	@PostMapping("/Reject/{id}")
	public ActionResult reject(@PathVariable("id") String id, @RequestBody FlowHandleModel flowHandleModel)
			throws WorkFlowException {
//        FlowTaskOperatorEntity flowTaskOperatorEntity = flowTaskOperatorService.getInfo(id);
		try {
			Task task = taskService.createTaskQuery().taskId(id).includeProcessVariables().singleResult();
			if (task == null) {
				return ActionResult.fail("拒绝失败");
			} else {

				LambdaQueryWrapper<FlowTaskOperatorEntity> lambdaQueryWrapper = new LambdaQueryWrapper();
				lambdaQueryWrapper.eq(FlowTaskOperatorEntity::getTaskNodeId, task.getId())
						.eq(FlowTaskOperatorEntity::getTaskId, task.getProcessInstanceId())
						.eq(FlowTaskOperatorEntity::getHandleId, userProvider.getUserId());
				List<FlowTaskOperatorEntity> list = flowTaskOperatorService.list(lambdaQueryWrapper);
				FlowModel flowModel = JsonUtil.getJsonToBean(flowHandleModel, FlowModel.class);
				flowTaskNewService.reject(list.get(0), flowModel, task);
				return ActionResult.success("拒绝成功");
			}
		} catch (Exception e) {
			e.printStackTrace();
			return ActionResult.fail("拒绝失败");
		}
	}

	/**
	 * 待我审核转办
	 *
	 * @param id              主键值
	 * @param flowHandleModel 经办信息
	 * @return
	 */
	@ApiOperation("待我审核转办")
	@PostMapping("/Transfer/{id}")
	public ActionResult transfer(@PathVariable("id") String id, @RequestBody FlowHandleModel flowHandleModel) {
//        FlowTaskOperatorEntity flowTaskOperatorEntity = flowTaskOperatorService.getInfo(id);
		Task task = taskService.createTaskQuery().taskId(id).singleResult();
		if (task == null) {
			return ActionResult.fail("转办失败");
		} else {
			taskService.unclaim(task.getId());
			taskService.claim(task.getId(), flowHandleModel.getFreeApproverUserId());
			taskService.setAssignee(task.getId(), flowHandleModel.getFreeApproverUserId());
			LambdaQueryWrapper<FlowTaskOperatorEntity> lambdaQueryWrapper = new LambdaQueryWrapper<>();
			lambdaQueryWrapper.eq(FlowTaskOperatorEntity::getTaskNodeId, task.getId())
					.eq(FlowTaskOperatorEntity::getHandleId, userProvider.getUserId());
			List<FlowTaskOperatorEntity> list = flowTaskOperatorService.list(lambdaQueryWrapper);
			FlowTaskOperatorEntity flowTaskOperatorEntity = list.get(0);
			flowTaskOperatorEntity.setHandleId(flowHandleModel.getFreeApproverUserId());
			flowTaskOperatorService.update(flowTaskOperatorEntity);
//            flowTaskOperatorEntity.setHandleId(flowHandleModel.getFreeApproverUserId());
//            flowTaskNewService.transfer(flowTaskOperatorEntity);
			return ActionResult.success("转办成功");
		}
	}

	/**
	 * 待我审核撤回审核(已办页面撤回)
	 * 注意：在撤销流程时要保证你的下一节点没有处理这条记录；如已处理则无法撤销流程。
	 *
	 * @param id              主键值
	 * @param flowHandleModel 实体对象
	 * @return
	 */
	@ApiOperation("待我审核撤回审核")
	@PostMapping("/Recall/{id}")
	public ActionResult recall(@PathVariable("id") String id, @RequestBody FlowHandleModel flowHandleModel)
			throws WorkFlowException {

		try {
			HistoricTaskInstance historicTaskInstance = historyService.createHistoricTaskInstanceQuery().taskId(id)
					.includeProcessVariables().singleResult();
			FlowModel flowModel = JsonUtil.getJsonToBean(flowHandleModel, FlowModel.class);
			flowTaskNewService.recall(id, flowModel, historicTaskInstance);
			return ActionResult.success("撤回成功");
		} catch (WorkFlowException e) {
			return ActionResult.fail(e.getMessage());
		} catch (Exception e) {
			e.printStackTrace();
			return ActionResult.fail("撤回失败");
		}
	}

	/**
	 * 待我审核终止审核
	 *
	 * @param id              主键值
	 * @param flowHandleModel 流程经办
	 * @return
	 */
	@ApiOperation("待我审核终止审核")
	@PostMapping("/Cancel/{id}")
	public ActionResult cancel(@PathVariable("id") String id, @RequestBody FlowHandleModel flowHandleModel)
			throws WorkFlowException {
		try {
			long count = runtimeService.createProcessInstanceQuery().processInstanceId(id).count();
			if (count != 0) {
				FlowModel flowModel = JsonUtil.getJsonToBean(flowHandleModel, FlowModel.class);
				flowTaskNewService.cancel(id, flowModel);
			}
			return ActionResult.success("终止审核成功");
		} catch (Exception e) {
			e.printStackTrace();
			return ActionResult.fail("终止审核失败");
		}
	}

	/**
	 * 指派人
	 *
	 * @param id              主键值
	 * @param flowHandleModel 流程经办
	 * @return
	 */
	@ApiOperation("指派人")
	@PostMapping("/Assign/{id}")
	public ActionResult assign(@PathVariable("id") String id, @RequestBody FlowHandleModel flowHandleModel) {
		try {
			boolean isOk = flowTaskNewService.assign(id, flowHandleModel);
			return isOk ? ActionResult.success("指派成功") : ActionResult.fail("指派失败");
		} catch (Exception e) {
			e.printStackTrace();
			return ActionResult.fail("指派失败");
		}
	}

}
