package cn.timer.api.utils.router;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.commons.collections4.ListUtils;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.convert.ConvertException;
import cn.hutool.core.lang.Console;
import cn.hutool.json.JSONObject;
import cn.timer.api.bean.spmk.SpmkApproveExecuteRecord;
import cn.timer.api.bean.spmk.SpmkApproveSummary;
import cn.timer.api.bean.spmk.SpmkExecutor;
import cn.timer.api.bean.yggl.YgglMainEmp;
import cn.timer.api.bean.zzgl.ZzglBmgwM;
import cn.timer.api.config.enuminterface.SpmkEnumInterface.ExecuteRecordSts;
import cn.timer.api.config.enuminterface.SpmkEnumInterface.ExecutorSts;
import cn.timer.api.config.enuminterface.SpmkEnumInterface.ParticipatorType;
import cn.timer.api.config.enums.CommonEnum;
import cn.timer.api.dto.spmk.Condition;
import cn.timer.api.dto.spmk.FlowChildren;
import cn.timer.api.dto.spmk.FromData;
import cn.timer.api.dto.spmk.Relation;
import cn.timer.api.dto.spmk.Router;
import cn.timer.api.dto.spmk.User;

/**
 * 流程节点工具类
 * 
 * @author Administrator
 *
 */
public class RouterUtils {
	/**
	 * 0 未执行
	 */
	private final static String UNEXECUTED = "0";
	/**
	 * 1 执行中
	 */
	private final static String EXECUTING = "1";
	/**
	 * 2 已执行
	 */
	private final static String EXECUTED = "2";
	/**
	 * creator 抄送人
	 */
	private final static String CREATOR = "creator";
	/**
	 * audit 审批人
	 */
	private final static String AUDIT = "audit";
	/**
	 * copy 抄送人
	 */
	private final static String COPY = "copy";
	/**
	 * department 部门类型
	 */
	private final static String RELATION_TYPE_DEPARTMENT = "department";
	/**
	 * users 用户类型
	 */
	private final static String RELATION_TYPE_USERS = "users";

	public static List<Router> NextNode(List<Router> listRouter,JSONObject obj, boolean isFirse) throws NumberFormatException, ConvertException, Exception {
		return NextNode(listRouter, obj, isFirse, false);
	}

	// 执行下一个节点
	public static List<Router> NextNode(List<Router> listRouter,JSONObject obj, boolean isFirse, boolean isAuditNext) throws NumberFormatException, ConvertException, Exception {
		
		Router router;
		if (CollectionUtil.isNotEmpty(listRouter)) {
			// 非条件节点
			if (listRouter.size() == 1) {
				router = listRouter.get(0);
				if (router.getExecute() == null) {
					System.out.println("默认UNEXECUTED");
					router.setExecute(UNEXECUTED);
				}
				// 0未执行 1执行中 2已执行
				switch (router.getExecute()) {
				case UNEXECUTED:
					switch (router.getClassName()) {
					case CREATOR:
						Console.log("发起人逻辑");
						router.setExecute(EXECUTED);
						router.setFlow(true);
						
						List<User> users = new ArrayList<User>();
						User userFirst =  User.builder()
								.name(obj.get("initiator",FromData.class).getValue())
								.id(obj.get("id",FromData.class).getValue())
								.headUrl(obj.get("headUrl",FromData.class).getValue())
								.execute(UNEXECUTED)
								.build();
						users.add(userFirst);
						List<Relation> relations = new ArrayList<Relation>();
						Relation relation = Relation.builder().type("user").users(users).build();
						relations.add(relation);
						
						router.setRelation(relations);
//						router.getRelation().get(0).setName(obj.get("initiator",FromData.class).getValue());
						
						NextNode(router.getChildren(),obj, isFirse, isAuditNext);
						break;
					case AUDIT:
						Console.log("审批人逻辑");
						router.setExecute(EXECUTING);
						router.setFlow(true);
						
						List<User> listUser = router.getRelation().get(0).getUsers();
						user:
							for (int i = 0; i < listUser.size(); i++) {
								String execute = listUser.get(i).getExecute();
								switch (execute) {
								case UNEXECUTED:
									listUser.get(i).setExecute(EXECUTING);
									// 首次发起申请时,写入 审批人名称 至 obj 中
									if (isFirse) {
										obj.set("current_approver", listUser.get(i).getName());
									}
									
									break user;
								}
							}
						isAuditNext = true;
						NextNode(router.getChildren(), obj , isFirse, isAuditNext);
						break;
					case COPY:
						if (!isAuditNext) {
							router.setExecute(EXECUTED);
						}
						Console.log("抄送人逻辑");
						router.setFlow(true);
						List<Relation> listRelations = router.getRelation();
						for (int i = 0; i < listRelations.size(); i++) {
							// 装配 部门人员
							if (RELATION_TYPE_DEPARTMENT.equals(listRelations.get(i).getType()) && listRelations.get(i).getDepartmentId() != null) {
								
								List<YgglMainEmp> listYgglMainEmp = selectOtherlistent(Integer.parseInt(obj.get("orgCode",FromData.class).getValue().trim()), Integer.valueOf(listRelations.get(i).getDepartmentId().trim()));
								
								if (listYgglMainEmp != null && listYgglMainEmp.size() > 0) {
									List<User> listUsers = new ArrayList<User>();
									for (YgglMainEmp emp : listYgglMainEmp) {
										User user = new User();
										user.setName(emp.getName());
										user.setId(String.valueOf(emp.getEmpNum()));
										listUsers.add(user);
									}
									listRelations.get(i).setUsers(listUsers);
								}else {
									listRelations.get(i).setUsers(null);
								}
								
								
							}else if (RELATION_TYPE_USERS.equals(listRelations.get(i).getType())) {

							}
						}
						NextNode(router.getChildren(), obj , isFirse, isAuditNext);
						break;
					}
					break;
				case EXECUTING:
					switch (router.getClassName()) {
					case AUDIT:
						router.setFlow(true);
						if (!isFirse) {
							Console.log("下一个审批人逻辑");
							boolean executeFlog = true;
							List<User> listUser = router.getRelation().get(0).getUsers();
							user:
								for (int i = 0; i < listUser.size(); i++) {
									String execute = listUser.get(i).getExecute();
									switch (execute) {
									case UNEXECUTED:
										listUser.get(i).setExecute(EXECUTING);
										executeFlog = false;
										break user;
									case EXECUTING:
										listUser.get(i).setExecute(EXECUTED);
										break;
									}
								}
							
							if (executeFlog) {
								router.setExecute(EXECUTED);
							}
							
						}
						NextNode(router.getChildren(),obj , isFirse, isAuditNext);
						break;
					}
					break;
				case EXECUTED:
					Console.log("下一个节点");
					NextNode(router.getChildren(),obj , isFirse, isAuditNext);
					break;
				}
				
			} else {
				// 条件节点
				rulefor:
				for (Router routerRule : listRouter) {
					switch (routerRule.getExecute()) {
					case UNEXECUTED:
						boolean condition_b = true;
						List<Condition> listCondition = routerRule.getCondition();
						if (listCondition == null || listCondition.size() == 0) {
							routerRule.setFlow(true);
						}else {
							Compare compare;
							for (Condition condition : listCondition) {
									for (String string : condition.getValues()) {
										
										// 简单工厂模式 - 判断条件
										compare = CompareFactory.createCompare(obj.get(condition.getKey(),FromData.class).getValue(), string, condition.getFormat());
										if (!compare.GetResutl()) {
											condition_b = false;
										}
										
									}
							}
						}
						
						routerRule.setFlow(condition_b);
						routerRule.setExecute(EXECUTED);
						if (routerRule.getFlow()) {
							Console.log("条件逻辑");
							NextNode(routerRule.getChildren(), obj , isFirse, isAuditNext);
						}
						break;
					case EXECUTED:
						if (routerRule.getFlow()) {
							NextNode(routerRule.getChildren(), obj , isFirse, isAuditNext);
						}
						break rulefor;
					}
					
				}
			
				Console.log("最后节点");
			}
		}

		return listRouter;

	};
	
	
	
	public static List<YgglMainEmp> selectOtherlistent(Integer orgCode, Integer id){
		ArrayList<Integer> list = new ArrayList<Integer>();
		List<ZzglBmgwM> zzglBmgwMs = ZzglBmgwM.builder().build().selectList(new QueryWrapper<ZzglBmgwM>().lambda()
				.eq(ZzglBmgwM::getOrgCode, orgCode));
		list.add(id);
		ZzglBmgwM.getDepts(list, id, zzglBmgwMs);

		if (list == null || list.size() == 0) {
			return null;
		} else {
			LambdaQueryWrapper<YgglMainEmp> ygglMainEmpsLambdaQueryWrapper = new LambdaQueryWrapper<>();
			ygglMainEmpsLambdaQueryWrapper
					.select(YgglMainEmp::getId, YgglMainEmp::getEmpNum, YgglMainEmp::getName, YgglMainEmp::getPhone,
							YgglMainEmp::getBmgwId)
					.eq(YgglMainEmp::getOrgCode, orgCode).and(i -> i.in(YgglMainEmp::getBmgwId, list.toArray()));
			List<YgglMainEmp> ygglMainEmps = YgglMainEmp.builder().build().selectList(ygglMainEmpsLambdaQueryWrapper);
			return ygglMainEmps;
		}

	}
	
	public static void getIsFlowChildren(List<Router> listRouter, List<FlowChildren> listFlowChildren) {
		// TODO Auto-generated method stub
		Router router;
		if (listRouter != null && listRouter.size() == 1) {
			router = listRouter.get(0);
			if (router.getFlow()) {
				FlowChildren fc = FlowChildren.builder().build();
				BeanUtil.copyProperties(router, fc, "condition","children");
				listFlowChildren.add(fc);
				getIsFlowChildren(router.getChildren(), listFlowChildren);
			}
			
		}else if (listRouter != null && listRouter.size() > 1) {
			for (Router router2 : listRouter) {
				if (router2.getFlow()) {
					getIsFlowChildren(router2.getChildren(), listFlowChildren);
				}
			}
		}

	};
	
	
	
	
	// 审批执行记录 持久化
	public static void insertogExecuteRecord(List<FlowChildren> listFlowChildren,Integer asId) throws Exception{

		for_insert:
		for (int i = 0,m = listFlowChildren.size() ; i < m; i++) {
			if (UNEXECUTED.equals(listFlowChildren.get(i).getExecute())) {
				i++;
				continue;
			}
				
			// ClassName 区分参与审批流程人的角色 CREATOR(发起人)、AUDIT(审核人)、COPY(抄送人)
			// 各个角色的逻辑不同
			switch (listFlowChildren.get(i).getClassName()) {
			case CREATOR:
				SpmkApproveExecuteRecord aer = SpmkApproveExecuteRecord
						.builder()
						.approveSummaryId(asId)
						.name(ParticipatorType.INITIATOR.getName())
						.type(ParticipatorType.INITIATOR.ordinal())
						.sts(ExecuteRecordSts.AGREE.ordinal())
						.build();
				// 新增 审批执行记录
				aer.insert();
				
				// 新增 执行人
				User user = listFlowChildren.get(i).getRelation().get(0).getUsers().get(0);
				SpmkExecutor.builder()
				.approveExecuteRecordId(aer.getId())
				.empNum(Integer.parseInt(user.getId()))
				.operatorHeaderUrl(user.getHeadUrl())
				.executorName(user.getName())
				.sts(ExecutorSts.AGREE.ordinal())
				.build()
				.insert();
				break;
			case AUDIT:
				SpmkApproveExecuteRecord aer2 = SpmkApproveExecuteRecord
				.builder()
				.approveSummaryId(asId)
				.name(ParticipatorType.APPROVER.getName())
				.type(ParticipatorType.APPROVER.ordinal())
				.sts(ExecuteRecordSts.IN_EXECUTION.ordinal())
				.build();
				// 新增 审批执行记录
				aer2.insert();

				// 新增 执行人
				List<User> listUser = listFlowChildren.get(i).getRelation().get(0).getUsers();
				
				for (User user2 : listUser) {
					SpmkExecutor executor = SpmkExecutor.builder()
					.approveExecuteRecordId(aer2.getId())
					.empNum(Integer.parseInt(user2.getId()))
					.operatorHeaderUrl(user2.getHeadUrl())
					.executorName(user2.getName())
					.build();
					switch (user2.getExecute()) {
					case EXECUTING:
						executor.setSts(ExecutorSts.IN_EXECUTION.ordinal());
						executor.insert();
						break for_insert;
					case EXECUTED:
						executor.setSts(ExecutorSts.AGREE.ordinal());
						executor.insert();
						break;
					}
				}
				break;
			case COPY:
				SpmkApproveExecuteRecord aer3 = SpmkApproveExecuteRecord
				.builder()
				.approveSummaryId(asId)
				.name(ParticipatorType.COPY.getName())
				.type(ParticipatorType.COPY.ordinal())
				.sts(ExecuteRecordSts.AGREE.ordinal())
				.build();
				// 新增 审批执行记录
				aer3.insert();

				List<Relation> listRelation = listFlowChildren.get(i).getRelation();
				
				for (Relation relation : listRelation) {
					List<User> listUser2 = relation.getUsers();
					
					// 新增 执行人
					for (User user2 : listUser2) {
						SpmkExecutor executor = SpmkExecutor.builder()
						.approveExecuteRecordId(aer3.getId())
						.empNum(Integer.parseInt(user2.getId()))
						.executorName(user2.getName())
						.operatorHeaderUrl(user2.getHeadUrl())
						.sts(ExecutorSts.AGREE.ordinal())
						.build();
						executor.insert();
					}
				}
				break;
			}
		}
	}
	
	/**
	 * 审批持久化
	 * @param listFlowChildren	节点
	 * @param asId				审批汇总Id
	 * @param executorId		执行人记录Id
	 * @param opinion			意见
	 * @param sts				状态 1执行中 2通过 3拒绝
	 */
	public static void approving(List<FlowChildren> listFlowChildren,Integer asId,Integer executeRecordId, Integer executorId, String opinion,Integer sts,User redeployUser ) throws Exception {
		
		boolean hasNextApprover = false;
		
		for (int i = 0,n = listFlowChildren.size(); i < n; i++) {

			// 新增 执行人
			List<User> listUser = listFlowChildren.get(i).getRelation().get(0).getUsers();
			if (EXECUTED.equals(listFlowChildren.get(i).getExecute())) {

			}else if (EXECUTING.equals(listFlowChildren.get(i).getExecute())) {
				
				for (int i_user = 0, n_user = listUser.size(); i_user < n_user; i_user++) {
					if (EXECUTED.equals(listUser.get(i_user).getExecute())) {
						
					}else if (EXECUTING.equals(listUser.get(i_user).getExecute())) {
						SpmkExecutor.builder()
							.id(executorId)
							.opinion(opinion)
							.empNum(Integer.parseInt(listUser.get(i_user).getId()))
							.executorName(listUser.get(i_user).getName())
							.operatorHeaderUrl(listUser.get(i_user).getHeadUrl())
							.sts(sts)
							.build()
						.updateById();
						listUser.get(i_user).setExecute(EXECUTED);
						
						// 历史审批人
						SpmkApproveSummary.builder().id(asId).historyApprover(listUser.get(i_user).getName()).build().updateById();
						// 0未执行 1执行中 2同意 3拒绝 4 转派
						if (sts == ExecutorSts.REFUSE.ordinal()) {
							// 更新 审批汇总 状态
							SpmkApproveSummary.builder().id(asId).currentApprover(CommonEnum.NULL_STR.getDesc()).endTime(new Date()).sts(sts).build().updateById();
							SpmkApproveExecuteRecord
									.builder()
									.id(executeRecordId)
									.sts(sts)
									.build()
									// 更新 审批执行记录
									.updateById();
							listFlowChildren.get(i_user).setExecute(EXECUTED);
							return;
						//转派 处理
						//在 原审批人 列表中 插入 一个被转派人(审批人)
						}else if (sts == ExecutorSts.REDEPLOY.ordinal()) {
							List<User> users1 = CollectionUtil.sub(listUser, 0, i_user+1);
							users1.add(redeployUser);
							List<User> users2 = CollectionUtil.sub(listUser, i_user+1, listUser.size());
							listUser = ListUtils.union(users1, users2);
							n_user = listUser.size();
						}
					}else if (UNEXECUTED.equals(listUser.get(i_user).getExecute())) {
						SpmkExecutor.builder()
							.approveExecuteRecordId(executeRecordId)
							.empNum(Integer.parseInt(listUser.get(i_user).getId()))
							.executorName(listUser.get(i_user).getName())
							.operatorHeaderUrl(listUser.get(i_user).getHeadUrl())
							.sts(ExecutorSts.IN_EXECUTION.ordinal())
							.build()
							.insert();
						hasNextApprover = true;
						listUser.get(i_user).setExecute(EXECUTING);
						
						// 当前审批人
						SpmkApproveSummary.builder().id(asId).currentApprover(listUser.get(i_user).getName()).build().updateById();
						
						// 处理了 下一个审批人 则跳出循环
						break;
					}
				}
				
				// 无下一个审批人 则更新 节点状态 为 EXECUTED(已执行)
				if (!hasNextApprover) {
					SpmkApproveExecuteRecord aer = SpmkApproveExecuteRecord
							.builder()
							.id(executeRecordId)
							.sts(ExecutorSts.AGREE.ordinal())
							.build();
							// 更新 审批执行记录
							aer.updateById();
					listFlowChildren.get(i).setExecute(EXECUTED);
				}
				
			}else if (UNEXECUTED.equals(listFlowChildren.get(i).getExecute())) {
				if (!hasNextApprover) {
					switch (listFlowChildren.get(i).getClassName()) {
					case CREATOR:
						SpmkApproveExecuteRecord aer = SpmkApproveExecuteRecord
								.builder()
								.approveSummaryId(asId)
								.name(ParticipatorType.INITIATOR.getName())
								.type(ParticipatorType.INITIATOR.ordinal())
								.sts(ExecuteRecordSts.AGREE.ordinal())
								.build();
						// 新增 审批执行记录
						aer.insert();
						
						// 新增 执行人
						User user = listFlowChildren.get(i).getRelation().get(0).getUsers().get(0);
						SpmkExecutor.builder()
						.approveExecuteRecordId(aer.getId())
						.empNum(Integer.parseInt(user.getId()))
						.executorName(user.getName())
						.operatorHeaderUrl(user.getHeadUrl())
						.sts(ExecutorSts.AGREE.ordinal())
						.build()
						.insert();
						
						listFlowChildren.get(i).setExecute(EXECUTED);
						break;
					case AUDIT:
						SpmkApproveExecuteRecord aer2 = SpmkApproveExecuteRecord
						.builder()
						.approveSummaryId(asId)
						.name(ParticipatorType.APPROVER.getName())
						.type(ParticipatorType.APPROVER.ordinal())
						.sts(ExecuteRecordSts.IN_EXECUTION.ordinal())
						.build();
						// 新增 审批执行记录
						aer2.insert();

						for (int i_user2 = 0,n_user2 = listUser.size(); i_user2 < n_user2; i_user2++) {
							SpmkExecutor executor = SpmkExecutor.builder()
									.approveExecuteRecordId(aer2.getId())
									.empNum(Integer.parseInt(listUser.get(i_user2).getId()))
									.executorName(listUser.get(i_user2).getName())
									.operatorHeaderUrl(listUser.get(i_user2).getHeadUrl())
									.sts(ExecutorSts.IN_EXECUTION.ordinal())
									.build();
									executor.insert();
									
									listUser.get(i_user2).setExecute(EXECUTING);
						}
						
						listFlowChildren.get(i).setExecute(EXECUTING);
						break;
					case COPY:
						SpmkApproveExecuteRecord aer3 = SpmkApproveExecuteRecord
						.builder()
						.approveSummaryId(asId)
						.name(ParticipatorType.COPY.getName())
						.type(ParticipatorType.COPY.ordinal())
						.sts(ExecuteRecordSts.AGREE.ordinal())
						.build();
						// 新增 审批执行记录
						aer3.insert();

						List<Relation> listRelation = listFlowChildren.get(i).getRelation();
						
						for (Relation relation : listRelation) {
							List<User> listUser2 = relation.getUsers();
							if (listUser2 != null) {
								// 新增 执行人
								for (User user2 : listUser2) {
									SpmkExecutor executor = SpmkExecutor.builder()
									.approveExecuteRecordId(aer3.getId())
									.empNum(Integer.parseInt(user2.getId()))
									.executorName(user2.getName())
									.operatorHeaderUrl(user2.getHeadUrl())
									.sts(ExecutorSts.AGREE.ordinal())
									.build();
									executor.insert();
								}
							}
						}
						
						listFlowChildren.get(i).setExecute(EXECUTED);
						break;
					}
				}
			}
		}
		
	}

}