package cz.muni.fi.pa165.core;

import io.swagger.v3.oas.models.security.SecurityRequirement;
import io.swagger.v3.oas.models.security.SecurityScheme;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springdoc.core.customizers.OpenApiCustomizer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.config.annotation.web.configurers.oauth2.server.resource.OAuth2ResourceServerConfigurer;

@SpringBootApplication
@EnableWebSecurity
@Import(MvcConfig.class)
public class CoreApplication {

  private static final Logger log = LoggerFactory.getLogger(CoreApplication.class);

  public static void main(String[] args) {
    SpringApplication.run(CoreApplication.class, args);
  }

  /**
   * Configure access restrictions to the API.
   * OIDC scopes are reused here for simplicity of the example, in real application new scopes would be used.
   * So it should be rather
   * <code>
   *  .requestMatchers(HttpMethod.GET, "/api/events").hasAuthority("SCOPE_calendar_read")
   *  .requestMatchers(HttpMethod.POST, "/api/events").hasAuthority("SCOPE_calendar_write")
   * </code>
   * Introspection of opaque access token is configured, introspection endpoint is defined in application.yml.
   */
  @Bean
  SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    http
            .authorizeHttpRequests(x -> x
                    .requestMatchers(HttpMethod.GET, "/*").hasAuthority("SCOPE_test_read")
                    .requestMatchers(HttpMethod.POST, "/*").hasAuthority("SCOPE_test_write")
                    .anyRequest().permitAll()
            )
            .csrf().disable()
            //.oauth2ResourceServer(OAuth2ResourceServerConfigurer::opaqueToken)
    ;
    return http.build();
  }

  /**
   * Add security definitions to generated openapi.yaml.
   */
  @Bean
  public OpenApiCustomizer openAPICustomizer() {
    return openApi -> {
      log.info("adding security to OpenAPI description");
      openApi.getComponents().addSecuritySchemes("BearerAuth",
              new SecurityScheme()
                      .scheme("bearer")
                      .type(SecurityScheme.Type.HTTP)
                      .description("OAuth2 Resource Server, provide a valid access token")
      );
      openApi.addSecurityItem(new SecurityRequirement().addList("BearerAuth"));
    };
  }
}
