package com.pingcap.community.blogserver.config;

import com.pingcap.community.blogserver.support.security.AccessTokenAuthenticationFilter;
import com.pingcap.community.blogserver.support.security.TidbCommunityAuthenticationFilter;
import java.util.*;
import lombok.AllArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
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.WebSecurityConfigurerAdapter;
import org.springframework.security.web.authentication.HttpStatusEntryPoint;
import org.springframework.security.web.session.SessionManagementFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import static org.springframework.security.config.Customizer.withDefaults;

@AllArgsConstructor
@EnableWebSecurity
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

  private final TidbCommunityAuthenticationFilter tidbCommunityAuthenticationFilter;

  private final AccessTokenAuthenticationFilter accessTokenAuthenticationFilter;

  private final BlogConfig blogConfig;

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http.csrf().disable();
    http.cors(withDefaults());
    http.addFilterAfter(accessTokenAuthenticationFilter, SessionManagementFilter.class)
        .exceptionHandling()
        .authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED))
        .and()
        .addFilterAfter(tidbCommunityAuthenticationFilter, SessionManagementFilter.class)
        .exceptionHandling()
        .authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED))
        .and()
        .authorizeRequests()
        .antMatchers("/devapi/**")
        .permitAll()
        .antMatchers(HttpMethod.GET, "/actuator/health/**")
        .permitAll()
        .antMatchers(HttpMethod.GET, "/api/**")
        .permitAll()
        .antMatchers(HttpMethod.POST, "/api/posts/{id}/share")
        .permitAll()
        .antMatchers(HttpMethod.POST, "/api/posts/{id}/visit")
        .permitAll()
        .antMatchers(HttpMethod.POST, "/internal/hooks/**")
        .permitAll()
        .anyRequest()
        .authenticated();
  }

  @Bean
  public CorsConfigurationSource corsConfigurationSource() {
    CorsConfiguration configuration = new CorsConfiguration();
    configuration.setAllowedOrigins(blogConfig.getCorsAllowedOrigins());
    configuration.setAllowedHeaders(List.of("*"));
    configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "PATCH", "DELETE"));
    configuration.setAllowCredentials(true);
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**", configuration);
    return source;
  }

}
