package com.mandi.system.utils;

import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.mapping.ParameterMode;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.type.TypeHandlerRegistry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;



import com.mandi.common.Jacksonmethod;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Properties;
import java.util.regex.Matcher;

@Intercepts({
		@Signature(type = Executor.class, method = "query", args = {
				MappedStatement.class, Object.class, RowBounds.class,
				ResultHandler.class }),
		@Signature(type = Executor.class, method = "update", args = {
				MappedStatement.class, Object.class }), })
public class MybatisSqlInterceptor implements Interceptor  {

	private Logger log = LoggerFactory
			.getLogger(MybatisSqlInterceptor.class);
	private Properties properties;
	private static final DateFormat DATE_FORMAT = new SimpleDateFormat(
			"yyyy-MM-dd HH:mm:ss");
	private static final DateFormat  SSS_FORMAT = new SimpleDateFormat(
			"hh:mm:ss.SSS");

	@Override
	public Object intercept(Invocation invocation) throws Throwable{
		MappedStatement mappedStatement = (MappedStatement) invocation
				.getArgs()[0];
		Object parameterObject = null;
		if (invocation.getArgs().length > 1) {
			parameterObject = invocation.getArgs()[1];
		}
		long start = System.currentTimeMillis();
		if(log.isInfoEnabled())
			log.info("s::intercept::"+mappedStatement.getId()+";sT:"+SSS_FORMAT.format(new Date()));
		Object result= invocation.proceed();
		long end = System.currentTimeMillis();
		if(log.isInfoEnabled())
			log.info("intercept::;eT:"+SSS_FORMAT.format(new Date())+";params::"+Jacksonmethod.tojson(parameterObject, false));
		long timing = end - start;

//		BoundSql boundSql = mappedStatement.getBoundSql(parameterObject);
//		Configuration configuration = mappedStatement.getConfiguration();
//		String sql = getSql(boundSql, parameterObject, configuration);
		if (log.isInfoEnabled()&&timing>Long.parseLong(String.valueOf(properties.get("notifyTime")))) {
			log.info("耗时:" + timing + " ms" );
		}
		return result;
	}

	@Override
	public Object plugin(Object target) {
		if (target instanceof Executor) {
			return Plugin.wrap(target, this);
		}
		return target;
	}

	@Override
	public void setProperties(Properties properties) {
		 this.properties = properties;
	}

	private String getSql(BoundSql boundSql, Object parameterObject,
			Configuration configuration) {
		String sql = boundSql.getSql().replaceAll("[\\s]+", " ");
		List<ParameterMapping> parameterMappings = boundSql
				.getParameterMappings();
		TypeHandlerRegistry typeHandlerRegistry = configuration
				.getTypeHandlerRegistry();
		if (parameterMappings != null) {
			for (int i = 0; i < parameterMappings.size(); i++) {
				ParameterMapping parameterMapping = parameterMappings.get(i);
				if (parameterMapping.getMode() != ParameterMode.OUT) {
					Object value;
					String propertyName = parameterMapping.getProperty();
					if (boundSql.hasAdditionalParameter(propertyName)) {
						value = boundSql.getAdditionalParameter(propertyName);
					} else if (parameterObject == null) {
						value = null;
					} else if (typeHandlerRegistry
							.hasTypeHandler(parameterObject.getClass())) {
						value = parameterObject;
					} else {
						MetaObject metaObject = configuration
								.newMetaObject(parameterObject);
						value = metaObject.getValue(propertyName);
					}
					sql = replacePlaceholder(sql, value);
				}
			}
		}
		return sql;
	}

	private String replacePlaceholder(String sql, Object propertyValue) {
		String result;
		if (propertyValue != null) {
			if (propertyValue instanceof String) {
				result = "'" + propertyValue + "'";
			} else if (propertyValue instanceof Date) {
				result = "'" + DATE_FORMAT.format(propertyValue) + "'";
			} else {
				result = propertyValue.toString();
			}
		} else {
			result = "null";
		}
		return sql.replaceFirst("\\?", Matcher.quoteReplacement(result));
	}
}