/**
 * Copyright (c) 2022 cloud Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.lutao.cloud.auth.handler;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.lutao.cloud.admin.api.dto.SysLogDTO;
import com.lutao.cloud.admin.api.feign.RemoteLogService;
import com.lutao.cloud.common.core.constant.SecurityConstants;
import com.lutao.cloud.common.core.util.KeyStrResolver;
import com.lutao.cloud.common.core.util.CloudWebUtils;
import com.lutao.cloud.common.log.util.LogTypeEnum;
import com.lutao.cloud.common.log.util.SysLogUtils;
import com.lutao.cloud.common.security.handler.AuthenticationFailureHandler;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

import org.springframework.data.redis.core.BoundValueOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.scheduling.annotation.Async;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

/**

 * @date 2018/10/8
 */
@Slf4j
@Component
@AllArgsConstructor
public class CloudAuthenticationFailureEventHandler implements AuthenticationFailureHandler{

	private final RemoteLogService logService;

	private final KeyStrResolver tenantKeyStrResolver;

	/**
	 * redis
	 */
	private final RedisTemplate redisTemplate;

	/**
	 * 异步处理，登录失败方法A
	 * <p>
	 * @param authenticationException 登录的authentication 对象
	 * @param authentication 登录的authenticationException 对象
	 * @param request 请求
	 * @param response 响应
	 * 登录失败后写入登录失败日志
	 */
	@Async
	@Override
	@SneakyThrows
	public void handle(AuthenticationException authenticationException, Authentication authentication,
			HttpServletRequest request, HttpServletResponse response){
		String username = authentication.getName();
		SysLogDTO sysLog = SysLogUtils.getSysLog(request, username);
		sysLog.setTitle(username + "用户登录");
		sysLog.setType(LogTypeEnum.ERROR.getType());
		sysLog.setParams(username);
		sysLog.setException(authenticationException.getLocalizedMessage());
		String header = request.getHeader(HttpHeaders.AUTHORIZATION);
		sysLog.setServiceId(CloudWebUtils.extractClientId(header).orElse("N/A"));
		sysLog.setTenantId(Integer.parseInt(tenantKeyStrResolver.key()));
		logService.saveLog(sysLog, SecurityConstants.FROM_IN);
		// 登录失败 5次锁定10分钟
		String key = String.format("user:error:count:%s",username);
		BoundValueOperations valueOps = redisTemplate.boundValueOps(key);
		Long count = valueOps.increment(1);
		valueOps.expire(600,TimeUnit.SECONDS);
		log.info("用户：{} 次数：{} 登录失败，异常：{}", username,count, authenticationException.getLocalizedMessage());
	}

}
