package com.hotent.base.filter;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.hotent.base.enums.ResponseErrorEnums;
import com.hotent.base.exception.BaseException;
import com.hotent.base.feign.PortalFeignService;
import com.hotent.base.feign.dto.PortalDataSensitive;
import com.hotent.base.groovy.GroovyScriptEngine;
import com.hotent.base.interceptor.ResultSetFilter;
import com.hotent.base.model.CommonResult;
import com.hotent.base.util.AppUtil;
import com.hotent.base.util.BeanUtils;
import com.hotent.base.util.ContextThread;
import com.hotent.base.util.JsonUtil;
import com.hotent.base.util.StringUtil;
import com.hotent.uc.api.util.IPermissionCalc;

/**
 * 表单数据格式化处理
 * @author jason
 *
 */
public class FormDataResultSetFilter implements ResultSetFilter,ContextThread {

	ThreadLocal<Map<String,PortalDataSensitive>> portalDataSensitiveLocal = new ThreadLocal<Map<String,PortalDataSensitive>>();


	@SuppressWarnings("unchecked")
	@Override
	public void handle(Object obj) {
		Map<String, Set<String>> currentProfiles = null;
		Map<String,PortalDataSensitive> portalDataSensitive = portalDataSensitiveLocal.get();
		if(BeanUtils.isNotEmpty(portalDataSensitive)) {
			IPermissionCalc permissionCalc = AppUtil.getBean(IPermissionCalc.class);
			currentProfiles = permissionCalc.getCurrentProfiles();
		}

		if(obj instanceof ArrayList) {
			ArrayList<HashMap<String, Object>> arrayList = (ArrayList<HashMap<String, Object>>) obj;
			for (HashMap<String, Object> hashMap : arrayList) {
				if(hashMap instanceof HashMap) {
					HashMap<String, Object> row = (HashMap<String, Object>) hashMap;
					for (Map.Entry<String, Object> entry : row.entrySet()) {
						// 判断字段是否设置了脱敏设置 已经设置的不能再更新到数据库
						if(BeanUtils.isNotEmpty(portalDataSensitive)) {
							handleField(entry,currentProfiles);
						}
					}

				}
			}
		}
		if(BeanUtils.isNotEmpty(portalDataSensitive)) {
			portalDataSensitiveLocal.remove();
		}

	}

	@Override
	public boolean support(String id, String sql, List<String> tableNames) {
		List<String> mappedStatementIds = new ArrayList<String>();
		// 报表查询
		mappedStatementIds.add("com.hotent.base.dao.CommonDao.queryByCustomSql");
		// 表单数据
		mappedStatementIds.add("com.hotent.base.dao.CommonDao.query");
		if(mappedStatementIds.contains(id)) {
			  PortalFeignService portalFeignService = AppUtil.getBean(PortalFeignService.class);
			  for (String tableName : tableNames) {
				  if(StringUtil.isNotEmpty(tableName)) {
					  CommonResult<PortalDataSensitive> portalDataSensitive = portalFeignService.getPortalDataSensitive("local",tableName);
					  if(BeanUtils.isNotEmpty(portalDataSensitive) &&
							  portalDataSensitive.getState() &&
							  BeanUtils.isNotEmpty(portalDataSensitive.getValue())) {
						  add2Local(tableName,portalDataSensitive.getValue());
					  }
				  }
			  }
			  return isNotEmpty();
		}

		return false;
	}
	
	private boolean isNotEmpty() {
		Map<String, PortalDataSensitive> map = portalDataSensitiveLocal.get();
		return BeanUtils.isNotEmpty(map);
	}
	
	
	private void add2Local(String tableName, PortalDataSensitive portalDataSensitive ) {
		Map<String, PortalDataSensitive> map = portalDataSensitiveLocal.get();
		if(BeanUtils.isEmpty(map)) {
			map = new HashMap<String, PortalDataSensitive>();
		}
		map.put(tableName, portalDataSensitive);
		portalDataSensitiveLocal.set(map);
	}
	
	private void handleField(Entry<String, Object> entry,  Map<String, Set<String>> currentProfiles) {
		try {
			Map<String, PortalDataSensitive> map = portalDataSensitiveLocal.get();
			Set<String> keySet = map.keySet();
			for (String tableName : keySet) {
				PortalDataSensitive portalDataSensitive = map.get(tableName);
				ArrayNode arrayNode = (ArrayNode) JsonUtil.toJsonNode(portalDataSensitive.getDesensitizationRules());
				GroovyScriptEngine groovyScriptEngine = AppUtil.getBean(GroovyScriptEngine.class);
				for (JsonNode jsonNode : arrayNode) {
					if(entry.getKey().equalsIgnoreCase(jsonNode.get("fieldName").asText())) {
						boolean hasRight = hasRight(jsonNode.get("rights").asText(),currentProfiles);
						if(!hasRight) {
							String groovyScript = jsonNode.get("groovyScript").asText();
							String calType = jsonNode.get("calType").asText();
							Object value = entry.getValue();
							Object workMask = value;
							if(StringUtil.isNotEmpty(groovyScript) && "2".equals(calType)) {
								Map<String, Object> vars = new HashMap<String, Object>();
								vars.put(entry.getKey(), entry.getValue());
								workMask = groovyScriptEngine.executeObject(groovyScript, vars);
							}else {
								int maxLength = 0;
								if(BeanUtils.isNotEmpty(value) && value instanceof String) {
									String valueStr = value.toString();
									maxLength = valueStr.length();
									JsonNode rules = JsonUtil.toJsonNode(jsonNode.get("rules").asText());
									int startPosition = rules.get("startPosition").asInt(0);
									if(startPosition>maxLength) {
										startPosition = maxLength;
									}
									int endPosition = rules.get("endPosition").asInt(maxLength);
									if(endPosition>maxLength) {
										endPosition = maxLength;
									}
									String pad = rules.get("pad").asText("*");
									workMask = StringUtil.wordMask(valueStr, startPosition, endPosition, pad);
								}
							}
							entry.setValue(workMask);
						}
					}
				}
			}
			
		} catch (IOException e) {
			throw new BaseException(ResponseErrorEnums.DESENSITIZATION);
		}
	}

	private boolean hasRight(String rights, Map<String, Set<String>> currentProfiles) throws IOException {
		IPermissionCalc permissionCalc = AppUtil.getBean(IPermissionCalc.class);
		ArrayNode arrayNode = (ArrayNode) JsonUtil.toJsonNode(rights);
		if (arrayNode.isEmpty()) {
			return false;
		}
		return permissionCalc.hasRight(JsonUtil.toJsonString(arrayNode.get(0)), currentProfiles);
	}

	@Override
	public void cleanAll() {
		portalDataSensitiveLocal.remove();
	}

}
