package com.style24.front.support.config;

import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.security.jackson2.SecurityJackson2Modules;
import org.springframework.session.data.redis.config.ConfigureRedisAction;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
import org.springframework.session.web.context.AbstractHttpSessionApplicationInitializer;
import org.springframework.session.web.http.CookieSerializer;
import org.springframework.session.web.http.DefaultCookieSerializer;

import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * Spring Session을 JSON 형태로 Redis에 저장하기 위한 Configuration
 * 		HttpSession 구현체를 대체하는 서블릿 필터를 생성
 *
 * 		@EnableRedisHttpSession 어노테이션은 SpringSessionRepositoryFilter(Filter의 구현체)라는 빈을 생성하는데,
 * 		yml 파일의 "spring.session.store-type: redis"와 같다.
 * 		이 필터는 HttpSession의 구현체를 바꾸는 역할을 한다.
 *
 *		@EnableRedisHttpSession 어노테이션을 하고
 *		"spring.data.redis.repositories.enabled: true" 속성을 application.yml 파일에 추가한다.
 *
 * @author gagamel
 * @since 2020. 9. 11
 */
@Configuration
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 1800)
public class TsfRedisSessionConfig extends AbstractHttpSessionApplicationInitializer implements BeanClassLoaderAware {

	private ClassLoader classLoader;

	@Override
	public void setBeanClassLoader(ClassLoader classLoader) {
		this.classLoader = classLoader;
	}

	/**
	 * Redis Keyspace Notification 역시 받을 필요가 없도록 처리
	 * @return
	 * @author gagamel
	 * @since 2020. 5. 31.
	 */
	@Bean
	public static ConfigureRedisAction configureRedisAction() {
		return ConfigureRedisAction.NO_OP;
	}

	/**
	 * Serialize 수행 방법을 스프링에 알려준다.
	 * @return
	 * @author gagamel
	 * @since 2020. 5. 29.
	 */
	@Bean
	public RedisSerializer<Object> springSessionDefaultRedisSerializer() {
		return new GenericJackson2JsonRedisSerializer(objectMapper());
	}

	/**
	 * Spring Security 관련 변수 및 매개 변수를 저장하기 위해 SecurityJackson2Modules를 사용
	 * @return
	 * @author gagamel
	 * @since 2020. 5. 29.
	 */
	private ObjectMapper objectMapper() {
		ObjectMapper mapper = new ObjectMapper();
		mapper.registerModules(SecurityJackson2Modules.getModules(this.classLoader));
		return mapper;
	}

	/**
	 * @EnableRedisHttpSession 어노테이션을 통해 redis-session을 처리할 경우
	 * 결제, 본인인증 후 콜백시 로그인이 풀림
	 * SAME_SITE = NONE 그리고 SECURE 를 하기위해서 해당 메소드가 필요함
	 * @return
	 * @author gagamel
	 * @since 2020. 5. 21.
	 */
	@Bean
	public CookieSerializer cookieSerializer() {
		DefaultCookieSerializer serializer = new DefaultCookieSerializer();
		serializer.setCookiePath("/");
		serializer.setUseBase64Encoding(false);

		// SSL인증서 적용 시 주석 제거
//		serializer.setUseSecureCookie(true);
//		serializer.setSameSite("NONE");

		return serializer;
	}

}
