package com.yeejoin.amos.boot.biz.common.service.impl;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.yeejoin.amos.boot.biz.common.bo.ReginParams;
import com.yeejoin.amos.boot.biz.common.enums.WorkFlowEnum;
import com.yeejoin.amos.boot.biz.common.service.IWorkflowExcuteService;
import com.yeejoin.amos.boot.biz.common.workflow.feign.WorkflowFeignService;

@Service
public class WorkflowExcuteServiceImpl implements IWorkflowExcuteService {

	@Autowired
	WorkflowFeignService workflowFeignService;

	@Transactional
	@Override
	public String startAndComplete(String key, String condition) throws Exception {
		JSONObject body = new JSONObject();
		String businessKey = buildOrderNo();
		body.put(WorkFlowEnum.BUSINESSKEY.getCode(), businessKey);
		body.put(WorkFlowEnum.processDefinitionKey.getCode(), key);
		JSONObject jsonObject = workflowFeignService.startByVariable(body);
		if (jsonObject == null || jsonObject.getJSONObject(WorkFlowEnum.DATA.getCode()) == null) {
			throw new RuntimeException("启动流程失败");
		}
		if (jsonObject != null) {
			JSONObject instance = jsonObject.getJSONObject(WorkFlowEnum.DATA.getCode());
			if (!excuteTask(instance.getString(WorkFlowEnum.ID.getCode()), condition)) {
				throw new RuntimeException("初始执行任务失败");
			}
		}
		return jsonObject.getJSONObject(WorkFlowEnum.DATA.getCode()).getString(WorkFlowEnum.ID.getCode());
	}

	@Override
	public boolean checkTaskAuth(String processInstanceId, ReginParams userInfo) {
		Map<String, Object> map = checkTaskAuthMap(processInstanceId, userInfo);
		return Boolean.parseBoolean(map.get(WorkFlowEnum.CHECKFLAG.getCode()).toString());
	}

	@Override
	public Map<String, Object> checkTaskAuthMap(String processInstanceId, ReginParams userInfo) {
		// 获取当前登录用户的角色
		String currentLoginUserRole = userInfo.getRole().getRoleName();
		String currentLoginUserName = userInfo.getUserModel().getUserName();
		Map<String, Object> map = new HashMap<String, Object>();
		map.put(WorkFlowEnum.CHECKFLAG.getCode(), false);
		JSONObject teskObject = workflowFeignService.getTaskList(processInstanceId);
		if (ObjectUtils.isNotEmpty(teskObject.getJSONArray(WorkFlowEnum.DATA.getCode()))) {
			JSONArray taskDetailArray = teskObject.getJSONArray(WorkFlowEnum.DATA.getCode());
			for (Object obj : taskDetailArray) {
				JSONObject detail = JSONObject.parseObject(JSONObject.toJSONString(obj));
				if (WorkFlowEnum.制定计划内容.getCode().equals(detail.getString(WorkFlowEnum.NAME.getCode()))
						|| WorkFlowEnum.现场确认.getCode().equals(detail.getString(WorkFlowEnum.NAME.getCode()))) {
					String groupName = getFristFlowDetail(processInstanceId);
					if (StringUtils.isNotBlank(groupName) && currentLoginUserRole.equals(groupName)) {
						map.put(WorkFlowEnum.TASKID.getCode(), detail.getString(WorkFlowEnum.ID.getCode()));
						map.put(WorkFlowEnum.CHECKFLAG.getCode(), true);
						map.put(WorkFlowEnum.NAME.getCode(), detail.getString(WorkFlowEnum.NAME.getCode()));
						return map;
					}
				}
				JSONObject taskGroupNameObject = workflowFeignService
						.getTaskGroupName(detail.getString(WorkFlowEnum.ID.getCode()));
				// 获取流程中原本设置的当前节点的执行权限
				JSONArray taskGroupNameDetail = taskGroupNameObject.getJSONArray(WorkFlowEnum.DATA.getCode());
				// 如果拿不到当前任务的执行角色，再去获取当前任务有没有默认的执行人，如果都没有则返回校验失败
				if (ObjectUtils.isEmpty(taskGroupNameDetail)) {
					JSONObject taskAssignObject = workflowFeignService
							.getTaskAssign(detail.getString(WorkFlowEnum.ID.getCode()));
					String assignUser = taskAssignObject.getJSONObject(WorkFlowEnum.DATA.getCode())
							.getString(WorkFlowEnum.ASSIGN.getCode());
					if (StringUtils.isNotBlank(assignUser)) {
						// 如果当前登录人与当前任务的设定人不一定，则直接返回权限校验失败
						if (!assignUser.contains(currentLoginUserName)) {
							return map;
						}
						map.put(WorkFlowEnum.TASKID.getCode(), detail.getString(WorkFlowEnum.ID.getCode()));
						map.put(WorkFlowEnum.CHECKFLAG.getCode(), true);
						map.put(WorkFlowEnum.NAME.getCode(), detail.getString(WorkFlowEnum.NAME.getCode()));
						map.put(WorkFlowEnum.ASSIGN.getCode(), assignUser);
						return map;
					}
					continue;
				}
				String defaultExecutionRoleProcess = taskGroupNameDetail.getJSONObject(0)
						.getString(WorkFlowEnum.GROUPID.getCode());
				
				if(StringUtils.isBlank(defaultExecutionRoleProcess)) {
					continue;
				}
				// 判断当前登录人的角色是不是与流程中设置的当前任务节点权限一致，一致则执行，不一致则退出
				if (!defaultExecutionRoleProcess.equals(currentLoginUserRole)) {
					continue;
				}
				map.put(WorkFlowEnum.TASKID.getCode(), detail.getString(WorkFlowEnum.ID.getCode()));
				map.put(WorkFlowEnum.CHECKFLAG.getCode(), true);
				map.put(WorkFlowEnum.NAME.getCode(), detail.getString(WorkFlowEnum.NAME.getCode()));
				map.put(WorkFlowEnum.GROUPNAME.getCode(), currentLoginUserRole);
			}
		}
		return map;
	}

	@Override
	public boolean excuteTask(String procressId, String condition) throws Exception {
		HashMap<String, Object> conditionMap = new HashMap<String, Object>();
		conditionMap.put(WorkFlowEnum.CONDITION.getCode(), condition);
		JSONObject teskObject = workflowFeignService.getTaskList(procressId);
		if (ObjectUtils.isNotEmpty(teskObject)) {
			JSONArray taskDetailArray = teskObject.getJSONArray(WorkFlowEnum.DATA.getCode());
			for (Object obj : taskDetailArray) {
				JSONObject detail = JSONObject.parseObject(JSONObject.toJSONString(obj));
				workflowFeignService.pickupAndCompleteTask(detail.getString(WorkFlowEnum.ID.getCode()), conditionMap);
			}
		}
		return true;
	}

	@Override
	public Object setTaskAssign(String processInstanceId, String userId) {
		JSONObject teskObject = workflowFeignService.getTaskList(processInstanceId);
		if (ObjectUtils.isEmpty(teskObject)) {
			throw new RuntimeException("设置任务执行人失败, 任务不存在，请检查processInstanceId" + processInstanceId + "是否正确");
		}
		JSONArray taskDetailArray = teskObject.getJSONArray(WorkFlowEnum.DATA.getCode());
		for (Object obj : taskDetailArray) {
			JSONObject detail = JSONObject.parseObject(JSONObject.toJSONString(obj));
			JSONObject taskGroupNameObject = workflowFeignService
					.getTaskGroupName(detail.getString(WorkFlowEnum.ID.getCode()));
			try {
				if (taskGroupNameObject.getJSONArray(WorkFlowEnum.DATA.getCode()) == null
						|| taskGroupNameObject.getJSONArray(WorkFlowEnum.DATA.getCode()).size() < 1) {
					workflowFeignService.setTaskUser(detail.getString(WorkFlowEnum.ID.getCode()), userId);
				}
			} catch (Exception e) {
				throw new RuntimeException("设置任务执行人失败");
			}
		}
		return true;
	}

	@Override
	public boolean CompleteTask(String processInstanceId, String condition, ReginParams userInfo) {
		Map<String, Object> map = checkTaskAuthMap(processInstanceId, userInfo);
		if (Boolean.parseBoolean(map.get(WorkFlowEnum.CHECKFLAG.getCode()).toString())) {
			HashMap<String, Object> conditionMap = new HashMap<String, Object>();
			conditionMap.put(WorkFlowEnum.CONDITION.getCode(), condition);
			try {
				workflowFeignService.pickupAndCompleteTask(map.get(WorkFlowEnum.TASKID.getCode()).toString(),
						conditionMap);
			} catch (Exception e) {
				throw new RuntimeException("完成任务失败");
			}
		} else {
			throw new RuntimeException("没有执行权限");
		}
		return true;
	}

	public static String buildOrderNo() {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		String newDate = sdf.format(new Date());
		String result = "";
		Random random = new Random();
		for (int i = 0; i < 3; i++) {
			result += random.nextInt(10);
		}
		return newDate + result;
	}

	/**
	 * 描述： 获取在流程启动时，直接完成的特定任务的执行角色信息。
	 * 作用：用来判断当前登录用户在任务回退到启动并完成的哪一步任务的执行权限，以及获取当前登录用户所属角色能够处理的当前任务的列表数据
	 * 
	 * @param processInstanceId
	 * @return
	 */
	public String getFristFlowDetail(String processInstanceId) {
		try {

			JSONObject historyTaskJsonObject = workflowFeignService
					.getHistoricTaskForProcessInstanceId(processInstanceId);
			if (ObjectUtils.isEmpty(historyTaskJsonObject.getJSONArray(WorkFlowEnum.DATA.getCode()))) {
				return null;
			}
			JSONObject historyTaskObject = historyTaskJsonObject.getJSONArray(WorkFlowEnum.DATA.getCode())
					.getJSONObject(0);
			JSONObject detail = workflowFeignService
					.getHistoricIdentityLinksForTask(historyTaskObject.getString(WorkFlowEnum.ID.getCode()));
			JSONArray resultArray = detail.getJSONArray(WorkFlowEnum.DATA.getCode());
			if (ObjectUtils.isNotEmpty(resultArray)) {
				for (int i = 0; i < resultArray.size(); i++) {
					JSONObject result = resultArray.getJSONObject(i);
					if (result.getBooleanValue(WorkFlowEnum.GROUP.getCode())) {
						return result.getString(WorkFlowEnum.GROUPID.getCode());
					}
				}
			}
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return null;
	}
/**
 * 获取当前登录用户所能执行的任务信息列表
 * @param key
 * @param userInfo
 * @return List<map<String,String>> eg: [{ "processInstanceId": "110d3af9-1f5a-11ec-a26e-b07b25133c48"}]
 * @throws Exception
 */
	public Object getCurrentUserAllTaskList(String key, ReginParams userInfo) throws Exception {
		String currentLoginUserRole = userInfo.getRole().getRoleName();
		JSONObject CurrentUserAllTaskResult = null;
		try {
			//获取该登录用户已经分配到他名下和他对应的角色权限所能执行的任务组
			CurrentUserAllTaskResult = workflowFeignService.getCurrentUserAllTaskList(key);
		} catch (Exception e) {
			throw new RuntimeException("获取当前角色所能执行的任务失败");
		}
		JSONArray allTaskResultList = CurrentUserAllTaskResult.getJSONArray(WorkFlowEnum.DATA.getCode());
		//获取制定计划节点任务的所有可执行任务
		JSONObject SpecifyTask = workflowFeignService.getTaskListForTaskName(WorkFlowEnum.制定计划内容.getCode(), key);
		JSONArray SpecifyTaskArray = SpecifyTask.getJSONArray(WorkFlowEnum.DATA.getCode());
		//判断该执行任务的历史执行节点的角色是否与当前登录用户的角色一致，如果一致就添加到根据用户角色ID和userID所属的任务列表中
		SpecifyTaskArray.stream().forEach(i -> {
			JSONObject json = JSONObject.parseObject(JSONObject.toJSONString(i));
			String groupName = getFristFlowDetail(json.getString(WorkFlowEnum.PROCESSINSTANCEID.getCode()));
			if (StringUtils.isNotBlank(groupName) && currentLoginUserRole.equals(groupName)) {
				allTaskResultList.add(i);
			}
		});
		return allTaskResultList;
	}

}
