package aiyh.utils.action;

import aiyh.utils.Util;
import aiyh.utils.excention.CustomerException;
import com.google.common.base.Strings;
import org.apache.log4j.Logger;
import org.jetbrains.annotations.NotNull;
import weaver.hrm.User;
import weaver.interfaces.workflow.action.Action;
import weaver.soa.workflow.request.*;
import weaver.workflow.request.RequestManager;
import weaver.workflow.workflow.WorkflowBillComInfo;
import weaver.workflow.workflow.WorkflowComInfo;

import java.util.*;
import java.util.stream.Collectors;

/**
 * <h1>基础的action,实现一些基础的参数</h1>
 *
 * @author EBU7-dev-1 aiyh
 */
public abstract class SafeCusBaseAction implements Action {
	
	
	/**
	 * 全局日志对象
	 */
	protected final Logger log = Util.getLogger();
	private final Map<String, SafeCusBaseActionHandleFunction> actionHandleMethod = new HashMap<>();
	
	/**
	 * <h2>初始化流程默认的处理方法</h2>
	 */
	private void initHandleMethod() {
		//        提交
		actionHandleMethod.put(ActionRunType.SUBMIT, this::doSubmit);
		//        退回
		actionHandleMethod.put(ActionRunType.REJECT, this::doReject);
		//        撤回
		actionHandleMethod.put(ActionRunType.WITHDRAW, this::doWithdraw);
		//        强制收回
		actionHandleMethod.put(ActionRunType.DRAW_BACK, this::doDrawBack);
	}
	
	
	@Override
	public final String execute(RequestInfo requestInfo) {
		RequestManager requestManager = requestInfo.getRequestManager();
		String billTable = requestManager.getBillTableName();
		String requestId = requestInfo.getRequestid();
		User user = requestInfo.getRequestManager().getUser();
		int workflowId = requestManager.getWorkflowid();
		//        操作类型 submit - 提交  reject - 退回 等
		String src = requestManager.getSrc();
		if ("".equals(billTable)) {
			WorkflowComInfo workflowComInfo = new WorkflowComInfo();
			String formId = workflowComInfo.getFormId(String.valueOf(workflowId));
			WorkflowBillComInfo workflowBillComInfo = new WorkflowBillComInfo();
			billTable = workflowBillComInfo.getTablename(formId);
		}
		try {
			Util.verifyRequiredField(this);
			if (!Strings.isNullOrEmpty(src)) {
				src = "submit";
			}
			//            初始化默认的流程处理方法
			initHandleMethod();
			//            提供自定义注册处理方法
			registerHandler(actionHandleMethod);
			//            获取流程对应的处理方法
			SafeCusBaseActionHandleFunction cusBaseActionHandleFunction = actionHandleMethod.get(src);
			//            默认没有直接成功不做拦截
			if (null == cusBaseActionHandleFunction) {
				return Action.SUCCESS;
			}
			cusBaseActionHandleFunction.handle(requestId, billTable, workflowId, user, requestInfo);
		} catch (CustomerException e) {
			if (e.getCode() != null && e.getCode() == 500) {
				Util.actionFail(requestManager, e.getMessage());
				return Action.FAILURE_AND_CONTINUE;
			}
			if (this.exceptionCallback(e, requestManager)) {
				return Action.FAILURE_AND_CONTINUE;
			}
		} catch (Exception e) {
			if (this.exceptionCallback(e, requestManager)) {
				return Action.FAILURE_AND_CONTINUE;
			}
		}
		return Action.SUCCESS;
	}
	
	
	/**
	 * <h2>程序执行异常回调</h2>
	 *
	 * @param e              异常信息
	 * @param requestManager requestManager对象
	 * @return 是否阻止action往下提交,true- 阻止, false-放行
	 */
	public boolean exceptionCallback(Exception e, RequestManager requestManager) {
		e.printStackTrace();
		log.error(Util.logStr("execute action fail, exception message is [{}], error stack trace msg is: \n{}",
				e.getMessage(), Util.getErrString(e)));
		Util.actionFail(requestManager, e.getMessage());
		return true;
	}
	
	
	/**
	 * <h2>流程其他流转类型处理方法注册</h2>
	 *
	 * @param actionHandleMethod 处理方法对应map
	 */
	public void registerHandler(Map<String, SafeCusBaseActionHandleFunction> actionHandleMethod) {
	}
	
	
	/**
	 * <h2>action 提交流程业务处理方法</h2>
	 * <p>具体业务逻辑实现
	 * 全局存在log成员变量,用于日志的输出 Util.actionFailException(requestManager,"error msg"); 用于提示action执行失败
	 * </p>
	 *
	 * @param requestId   流程请求ID
	 * @param billTable   流程对应主表名称
	 * @param workflowId  流程对应流程ID
	 * @param user        当前节点操作者用户
	 * @param requestInfo 请求管理对象
	 */
	
	public abstract void doSubmit(String requestId, String billTable, int workflowId,
	                              User user, RequestInfo requestInfo);
	
	
	/**
	 * <h2>action 退回流程业务处理方法</h2>
	 * <p>具体业务逻辑实现
	 * 全局存在log成员变量,用于日志的输出 Util.actionFailException(requestManager,"error msg"); 用于提示action执行失败
	 * </p>
	 *
	 * @param requestId   流程请求ID
	 * @param billTable   流程对应主表名称
	 * @param workflowId  流程对应流程ID
	 * @param user        当前节点操作者用户
	 * @param requestInfo 请求管理对象
	 */
	public void doReject(String requestId, String billTable, int workflowId,
	                     User user, RequestInfo requestInfo) {
	}
	
	/**
	 * <h2>action 撤回、撤回流程流程业务处理方法</h2>
	 * <p>具体业务逻辑实现
	 * 全局存在log成员变量,用于日志的输出 Util.actionFailException(requestManager,"error msg"); 用于提示action执行失败
	 * </p>
	 *
	 * @param requestId   流程请求ID
	 * @param billTable   流程对应主表名称
	 * @param workflowId  流程对应流程ID
	 * @param user        当前节点操作者用户
	 * @param requestInfo 请求管理对象
	 */
	public void doWithdraw(String requestId, String billTable, int workflowId,
	                       User user, RequestInfo requestInfo) {
	}
	
	
	/**
	 * <h2>action 强制收回流程业务处理方法</h2>
	 * <p>具体业务逻辑实现
	 * 全局存在log成员变量,用于日志的输出 Util.actionFailException(requestManager,"error msg"); 用于提示action执行失败
	 * </p>
	 *
	 * @param requestId   流程请求ID
	 * @param billTable   流程对应主表名称
	 * @param workflowId  流程对应流程ID
	 * @param user        当前节点操作者用户
	 * @param requestInfo 请求管理对象
	 */
	public void doDrawBack(String requestId, String billTable, int workflowId,
	                       User user, RequestInfo requestInfo) {
	}
	
	/**
	 * <h2>获取流程主表数据</h2>
	 *
	 * @return 流程主表数据
	 */
	protected Map<String, String> getMainTableValue(RequestInfo requestInfo) {
		//        获取主表数据
		Property[] propertyArr = requestInfo.getMainTableInfo().getProperty();
		return getStringMap(propertyArr);
	}
	
	@NotNull
	private Map<String, String> getStringMap(Property[] propertyArr) {
		if (null == propertyArr) {
			return Collections.emptyMap();
		}
		Map<String, String> mainTable = new HashMap<>((int) Math.ceil(propertyArr.length * 1.4));
		for (Property property : propertyArr) {
			String fieldName = property.getName();
			String value = property.getValue();
			mainTable.put(fieldName, value);
		}
		return mainTable;
	}
	
	/**
	 * <h2>获取流程主表数据</h2>
	 *
	 * @return 流程主表数据
	 */
	protected Map<String, Object> getObjMainTableValue(RequestInfo requestInfo) {
		Map<String, String> mainTableValue = getMainTableValue(requestInfo);
		return new HashMap<>(mainTableValue);
	}
	
	
	/**
	 * <h2>获取所有明细数据</h2>
	 *
	 * @return 以明细表需要为键,以明细表数据为值的键值对明细数据信息
	 */
	protected Map<String, List<Map<String, String>>> getDetailTableValue(RequestInfo requestInfo) {
		DetailTable[] detailTableArr = requestInfo.getDetailTableInfo().getDetailTable();
		return getListMap(detailTableArr);
	}
	
	/**
	 * <h2>获取所有明细数据</h2>
	 *
	 * @return 以明细表需要为键,以明细表数据为值的键值对明细数据信息
	 */
	protected Map<String, List<Map<String, Object>>> getDetailTableObjValue(RequestInfo requestInfo) {
		DetailTable[] detailTableArr = requestInfo.getDetailTableInfo().getDetailTable();
		Map<String, List<Map<String, String>>> listMap = getListMap(detailTableArr);
		Map<String, List<Map<String, Object>>> result = new HashMap<>(listMap.size());
		for (Map.Entry<String, List<Map<String, String>>> entry : listMap.entrySet()) {
			List<Map<String, String>> list = entry.getValue();
			List<Map<String, Object>> collect = list.stream().map(item -> new HashMap<String, Object>(item)).collect(Collectors.toList());
			result.put(entry.getKey(), collect);
		}
		return result;
	}
	
	
	@NotNull
	private Map<String, List<Map<String, String>>> getListMap(DetailTable[] detailTableArr) {
		Map<String, List<Map<String, String>>> detailDataList = new HashMap<>((int) Math.ceil(detailTableArr.length * 1.4));
		for (DetailTable detailTable : detailTableArr) {
			List<Map<String, String>> detailData = getDetailValue(detailTable);
			detailDataList.put(detailTable.getId(), detailData);
		}
		return detailDataList;
	}
	
	
	/**
	 * <h2>获取指定明细表的表数据</h2>
	 *
	 * @param detailNo 明细表编号
	 * @return 明细数据
	 */
	protected List<Map<String, String>> getDetailTableValueByDetailNo(int detailNo, RequestInfo requestInfo) {
		DetailTable detailTable = requestInfo.getDetailTableInfo().getDetailTable(detailNo);
		return getDetailValue(detailTable);
	}
	
	/**
	 * <h2>获取指定明细表的表数据</h2>
	 *
	 * @param detailNo 明细表编号
	 * @return 明细数据
	 */
	protected List<Map<String, Object>> getDetailTableObjValueByDetailNo(int detailNo, RequestInfo requestInfo) {
		DetailTable detailTable = requestInfo.getDetailTableInfo().getDetailTable(detailNo);
		List<Map<String, String>> detailValue = getDetailValue(detailTable);
		return detailValue.stream().map(item -> new HashMap<String, Object>(item)).collect(Collectors.toList());
	}
	
	/**
	 * <h2>根据明细表信息获取明细表数据</h2>
	 *
	 * @param detailTable 明细表对象
	 * @return 明细表数据
	 */
	@NotNull
	private List<Map<String, String>> getDetailValue(DetailTable detailTable) {
		Row[] rowArr = detailTable.getRow();
		List<Map<String, String>> detailData = new ArrayList<>(rowArr.length);
		for (Row row : rowArr) {
			Cell[] cellArr = row.getCell();
			Map<String, String> rowData = new HashMap<>((int) Math.ceil(cellArr.length * (1 + 0.4)));
			rowData.put("id", row.getId());
			for (Cell cell : cellArr) {
				String fieldName = cell.getName();
				String value = cell.getValue();
				rowData.put(fieldName, value);
			}
			detailData.add(rowData);
		}
		return detailData;
	}
	
	
	public static final class ActionRunType {
		/**
		 * 退回
		 */
		public static final String REJECT = "reject";
		/**
		 * 撤回
		 */
		public static final String WITHDRAW = "withdraw";
		/**
		 * 强制收回
		 */
		public static final String DRAW_BACK = "drawBack";
		/**
		 * 提交
		 */
		public static final String SUBMIT = "submit";
	}
	
}