
package org.tio.sitexxx.server.http;

import cn.hutool.core.util.StrUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.tio.http.common.HeaderName;
import org.tio.http.common.HeaderValue;
import org.tio.http.common.HttpRequest;
import org.tio.http.common.HttpResponse;
import org.tio.http.common.session.limiter.SessionRateLimiter;
import org.tio.http.common.session.limiter.SessionRateVo;
import org.tio.sitexxx.service.vo.AppCode;
import org.tio.utils.SystemTimer;
import org.tio.utils.json.Json;
import org.tio.utils.resp.Resp;

import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

public class WebApiSessionRateLimiter implements SessionRateLimiter {
	public static final WebApiSessionRateLimiter me = new WebApiSessionRateLimiter();
	private static Logger log = LoggerFactory.getLogger(WebApiSessionRateLimiter.class);
	/**
	 * key:   访问路径<br>
	 * value: 相邻两次访问必须间隔的最小时间，单位：毫秒<br>
	 */
	private final Map<String, Integer> intervalMap = new HashMap<>();

	/**
	 * key:   访问路径的前缀<br>
	 * value: 相邻两次访问必须间隔的最小时间，单位：毫秒<br>
	 */
	private final Map<String, Integer> prefixMap = new HashMap<>();

	/**
	 * 每分钟允许访问的次数
	 */
	private final Map<String, Integer> allowCountMap = new HashMap<>();

	private HttpResponse response;

	private WebApiSessionRateLimiter() {

		intervalMap.put("/logout", 2000);

		intervalMap.put("/register/submit", 5000); //注册
		intervalMap.put("/register/retrievePwd", 5000); //找回密码步骤一，发邮件
		intervalMap.put("/register/setNewPwd", 5000); //找回密码步骤二，设置密码

		intervalMap.put("/wx/friend/applyFriend", 4000);// 请求添加好友
		intervalMap.put("/chat/createGroup", 3000);//3秒内只能创建一个群

		allowCountMap.put("/chat/msgOper", 1000);
		allowCountMap.put("/login", 12);
		allowCountMap.put("/user/search", 230); //用户搜索

		allowCountMap.put("/wx/friend/replyApplyFriend", 160); // 同意或拒绝某人添加自己为好友
		allowCountMap.put("/chat/list", 160);
		allowCountMap.put("/chat/group", 60);
		allowCountMap.put("/chat/forbidden",300);
		allowCountMap.put("/user/teamList", 1000);
		allowCountMap.put("/syn/chat", 100);
		allowCountMap.put("/chat/selectNotice", 100);

		response = new HttpResponse();
		response.setBody(Json.toJson(Resp.fail("操作太快，请稍后操作").code(AppCode.ForbidOper.REFUSE)).getBytes(StandardCharsets.UTF_8));
		response.addHeader(HeaderName.Content_Type, HeaderValue.Content_Type.TEXT_PLAIN_JSON);
	}

	@Override
	public boolean allow(HttpRequest request, SessionRateVo sessionRateVo) {
		String path = request.getRequestLine().getPath();

		Integer allowCount = allowCountMap.get(path);
		if (allowCount == null) {
			allowCount = 30;
		}
		if (sessionRateVo.getAccessCount().get() > allowCount) {
			log.error("path({}), access count of curr session({}) is greater than allow count({})", path, sessionRateVo.getAccessCount().get(), allowCount);
			return false;
		}

		Integer iv = intervalMap.get(path);
		if (iv == null) {
			if (prefixMap.size() > 0) {
				Set<Entry<String, Integer>> set = prefixMap.entrySet();
				for (Entry<String, Integer> entry : set) {
					if (StrUtil.startWith(path, entry.getKey())) {
						iv = entry.getValue();
						break;
					}
				}
			}
		}

		if (iv != null) {
			if (SystemTimer.currTime - sessionRateVo.getLastAccessTime() < iv) {
				log.error("path({}), curr time ({}) - last access time ({}) < iv({})", path, SystemTimer.currTime, sessionRateVo.getLastAccessTime(), iv);
				return false;
			}
		}

		return true;
	}

	@Override
	public HttpResponse response(HttpRequest request, SessionRateVo sessionRateVo) {
		return response;
	}

}
