package com.xunhong.erp.turbo.web.interceptor;

import com.xunhong.erp.turbo.web.annotation.RepeatSubmit;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.AsyncHandlerInterceptor;

import java.lang.reflect.Method;
import java.util.Map;
import java.util.Objects;

/**
 * @author shenyifei
 */
@Slf4j
@Component
public class RepeatSubmitInterceptor implements AsyncHandlerInterceptor {

	public static final String SET_VAL = "1";

	@Autowired
	private RedisTemplate<Object, Object> redisTemplate;

	/**
	 * 根据请求获取客户端Ip地址
	 *
	 * @param request Servlet请求
	 * @return 返回IP地址
	 */
	public static String getClientIp(HttpServletRequest request) {
		String unknown = "unknown";
		if (request == null) {
			return unknown;
		}
		String ip = request.getHeader("x-forwarded-for");
		if (ip == null || ip.length() == 0 || unknown.equalsIgnoreCase(ip)) {
			ip = request.getHeader("Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || unknown.equalsIgnoreCase(ip)) {
			ip = request.getHeader("X-Forwarded-For");
		}
		if (ip == null || ip.length() == 0 || unknown.equalsIgnoreCase(ip)) {
			ip = request.getHeader("WL-Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || unknown.equalsIgnoreCase(ip)) {
			ip = request.getHeader("X-Real-IP");
		}

		if (ip == null || ip.length() == 0 || unknown.equalsIgnoreCase(ip)) {
			ip = request.getRemoteAddr();
		}
		return ip;
	}

	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
		//如果没有映射到方法直接通过
		if (!(handler instanceof HandlerMethod)) {
			return true;
		}
		HandlerMethod handlerMethod = (HandlerMethod) handler;
		Method method = handlerMethod.getMethod();
		RepeatSubmit repeatSubmit = method.getAnnotation(RepeatSubmit.class);
		if (Objects.isNull(repeatSubmit)) {
			return true;
		}
		long limitTime = repeatSubmit.limitTime();
		String ip = getClientIp(request);
		//获取请求参数
		Map query = request.getParameterMap();
		//目标类、方法
		String className = method.getDeclaringClass().getName();
		String name = method.getName();
		String ipKey = String.format("%s#%s#%s#%s", ip, className, name, query);
		log.info("className:{},name:{},ip:{},query:{}", className, name, ip, query.toString());
		int hashCode = Math.abs(ipKey.hashCode());
		String key = String.format("%s_%d", ip, hashCode);
		Object objValue = redisTemplate.opsForValue().get(key);
		if (Objects.nonNull(objValue)) {
			String strValue = objValue.toString();
			if (SET_VAL.equals(strValue)) {
				log.error("路径：{}，访问：{}重复", request.getServletPath(), ipKey);
				throw new RuntimeException("可能存在重复操作，请稍后再试");
			}
		}
		redisTemplate.opsForValue().set(key, SET_VAL, limitTime);
		return true;
	}
}
