package com.dbnt.sims.config;

import com.dbnt.sims.userInfo.model.UserInfo;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.crypto.password.Pbkdf2PasswordEncoder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
import org.springframework.security.web.savedrequest.SavedRequest;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import javax.servlet.http.HttpServletResponse;

@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig{
  private final Logger log = LoggerFactory.getLogger(getClass());
  private final BaseController baseController;

  @Bean
  public PasswordEncoder passwordEncoder(){
    return new Pbkdf2PasswordEncoder();
  }

  @Bean
  public WebSecurityCustomizer webSecurityCustomizer() {
    return (web) -> web.ignoring().antMatchers("/css/**", "/img/**", "/js/**", "/vendor/**");
  }

  @Bean
  public AccessDeniedHandler accessDeniedHandler() {
    log.warn("accessDeniedHandler");
    return (request, response, e) -> {
      response.setStatus(HttpServletResponse.SC_FORBIDDEN);
      response.setContentType("text/html;charset=UTF-8");
      response.getWriter().println("<script>alert('접근이 거부되었습니다.'); location.href='/';</script>");
      response.getWriter().flush();
      response.getWriter().close();
    };
  }

  @Bean
  public AuthenticationEntryPoint authenticationEntryPoint() {
    return (request, response, e) -> {
      response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
      response.setContentType("text/html;charset=UTF-8");
      response.getWriter().println("<script>alert('로그인이 해제되었습니다.'); location.href='/';</script>");
      response.getWriter().flush();
      response.getWriter().close();
    };
  }

  @Bean
  public AuthenticationSuccessHandler loginSuccessHandler() {
    return (request, response, authentication) -> {
      SavedRequest savedRequest = new HttpSessionRequestCache().getRequest(request,response);
      baseController.setSession((UserInfo)authentication.getPrincipal(), request.getSession());
      if(savedRequest != null){
        String targetUrl = savedRequest.getRedirectUrl();
        new DefaultRedirectStrategy().sendRedirect(request,response,targetUrl);
      }else{
        new DefaultRedirectStrategy().sendRedirect(request,response,"/");
      }
    };
  }

  @Bean
  protected SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http.authorizeRequests() // 페이지 권한 설정
          .antMatchers(
              "/dashboard",
              "/myInfo/**",
              "/modal/**",
              "/publicBoard/**",
              "/faRpt/**",
              "/affairPlan/**",
              "/affair/**",
              "/affairResult/**",
              "/equip/**",
              "/target/**",
              "/translator/**"
          ).hasRole(Role.USER.name()) // USER 접근 허용
          .antMatchers(
              "/authMgt/**",
              "/userMgt/**",
              "/organMgt/**"
          ).hasRole(Role.SUB_ADMIN.name()) // SUB_ADMIN 접근 허용
          .antMatchers(
              "/codeMgt/**",
              "/menuMgt/**"
          ).hasRole(Role.ADMIN.name()) // ADMIN 접근 허용
          .antMatchers("/login").permitAll() // 로그인 페이지는 권한 없이 접근 허용
        .and() // 로그인 설정
          .formLogin().loginPage("/login") // Custom login form 사용
          .failureUrl("/login-error") // 로그인 실패 시 이동
          .defaultSuccessUrl("/") // 로그인 성공 시 이동
          /*.failureHandler((request, response, exception) -> {

          })*/ // 로그인 실패시 동작 수행
          .successHandler(loginSuccessHandler()) // 로그인 성공시 동작 수행.
        .and() // 로그아웃 설정
          .logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout")) // 로그아웃 시 URL 재정의
          .logoutSuccessUrl("/") // 로그아웃 성공 시 redirect 이동
          .invalidateHttpSession(true) // HTTP Session 초기화
          .deleteCookies("JSESSIONID") // 특정 쿠키 제거
        .and() // 403 예외처리 핸들링
          //.exceptionHandling().accessDeniedPage("/denied");
          .exceptionHandling()
          .accessDeniedHandler(accessDeniedHandler())
          .authenticationEntryPoint(authenticationEntryPoint());
    return http.build();
  }

}
