package app.config;

import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;


import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.AuthenticationEventPublisher;
import org.springframework.security.authentication.event.AuthenticationSuccessEvent;
import org.springframework.security.authentication.event.AuthenticationFailureBadCredentialsEvent;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository; // "C:\Users\tim\Documents\projects\Login2\jars\spring-security-web-6.4.2.jar"
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl; // "C:\Users\tim\Documents\projects\Login2\jars\spring-security-web-6.4.2.jar"


/**
 *  
 * @author tim
 */
@Configuration
@EnableWebSecurity
public class SecurityConfiguration {

    public static final String USER = "ROLE_USER";
    public static final String ADMIN = "ROLE_ADMIN";
    public static final String SYSOP = "ROLE_SYSOP";
    public static final String OIDC_USER = "OIDC_USER";

    @Autowired
    private UserDetailsService myUserDetailsService;

    //@Autowired
    //@Qualifier("delegatedAuthenticationEntryPoint")
    //AuthenticationEntryPoint authEntryPoint;

    @Autowired
    DataSource dataSource;
    
    @Bean
    public PersistentTokenRepository persistentTokenRepository() {
        JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();
        tokenRepository.setDataSource(dataSource); // Inject your DataSource
        return tokenRepository;
    }

    @Bean
    @Order(1)
    SecurityFilterChain filterChain(HttpSecurity http, AuthenticationEventPublisher publisher) throws Exception {
        String[] allowedPaths = { "/register", "/activate",  
            "/webjars/**", "/**.css", "/resources/**", "/logout/**", "/error/**", 
            "/reset_pass", "/request_reset_pass_link"
        };
        http
            .authorizeHttpRequests(auth -> {
                auth.requestMatchers("/account/user_type_redirect").authenticated();
                auth.requestMatchers("/account/change_pass").authenticated();
                auth.requestMatchers("/account/user/**").hasRole("USER");
                auth.requestMatchers("/account/admin/**").hasRole("ADMIN");
                auth.requestMatchers("/account/sysop/**").hasRole("SYSOP");
                auth.requestMatchers(allowedPaths).permitAll();
                //auth.requestMatchers("/").permitAll();
                auth.anyRequest().denyAll();
            }) 
            .csrf(Customizer.withDefaults())
            .logout(logout -> logout
                .logoutUrl("/logout") 
                .invalidateHttpSession(true)
                .deleteCookies("JSESSIONID") 
                .permitAll()
            )    
            .userDetailsService(myUserDetailsService)
            .httpBasic(Customizer.withDefaults())
            .formLogin(form -> form
                .loginPage("/login")
                .successForwardUrl("/account/user_type_redirect")
                .permitAll()
            ) 
            .rememberMe(rememberMe -> rememberMe
                .tokenRepository(persistentTokenRepository())
                .userDetailsService(myUserDetailsService) 
            )
            .oauth2Login(oauth2Login -> oauth2Login
                .loginPage("/login")
                .permitAll()
            )
            ;
        return http.build();
    }
    
    @Bean
    public PasswordEncoder passwordEncoder() {
        //return NoOpPasswordEncoder.getInstance();
        return new BCryptPasswordEncoder(17);
    }

    @Bean
    public ApplicationListener<AuthenticationSuccessEvent> successEvent() {
        return event -> {
            System.err.println("\n\nSuccess Login " + event.getAuthentication().getClass().getName() + " - " + event.getAuthentication().getName() + "\n\n");
        };
    }

    @Bean
    public ApplicationListener<AuthenticationFailureBadCredentialsEvent> failureEvent() {
        return event -> {
            System.err.println("\n\nBad Credentials Login " + event.getAuthentication().getClass().getName() + " - " + event.getAuthentication().getName() + "\n\n");
        };
    }
    
}
