package com.imprimelibros.erp.config;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;

import com.imprimelibros.erp.users.User;
import com.imprimelibros.erp.users.UserDao;
import com.imprimelibros.erp.users.UserDetailsImpl;

@Configuration
public class SecurityConfig {

    private final DataSource dataSource;

    public SecurityConfig(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    // ========== Beans base ==========

    @Bean
    public UserDetailsService userDetailsService(UserDao repo) {
        return username -> {
            User u = repo.findByUserNameAndEnabledTrue(username);
            if (u == null) throw new UsernameNotFoundException("No existe: " + username);
            return new UserDetailsImpl(u);
        };
    }

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

    // Provider que soporta UsernamePasswordAuthenticationToken
    @Bean
    public AuthenticationProvider daoAuthenticationProvider(
            UserDetailsService userDetailsService,
            PasswordEncoder passwordEncoder) {

        DaoAuthenticationProvider p = new DaoAuthenticationProvider();
        p.setUserDetailsService(userDetailsService);
        p.setPasswordEncoder(passwordEncoder);
        return p;
    }

    // Remember-me (tabla persistent_logins)
    @Bean
    public PersistentTokenRepository persistentTokenRepository() {
        JdbcTokenRepositoryImpl repo = new JdbcTokenRepositoryImpl();
        repo.setDataSource(dataSource);
        // repo.setCreateTableOnStartup(true); // solo 1ª vez si necesitas crear la tabla
        return repo;
    }

    // ========== Filtro de seguridad ==========
    @Bean
    public SecurityFilterChain securityFilterChain(
            HttpSecurity http,
            @Value("${security.rememberme.key}") String keyRememberMe,
            UserDetailsService userDetailsService,
            PersistentTokenRepository tokenRepo,
            AuthenticationProvider daoAuthenticationProvider
    ) throws Exception {

        http
            // Registra explícitamente el provider para Username/Password
            .authenticationProvider(daoAuthenticationProvider)

            .sessionManagement(session -> session
                .invalidSessionUrl("/login?expired")
                .maximumSessions(1)
            )

            .csrf(csrf -> csrf
                .ignoringRequestMatchers("/presupuesto/public/**")
            )

            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/", "/login",
                    "/assets/**", "/css/**", "/js/**", "/images/**",
                    "/public/**", "/presupuesto/public/**",
                    "/error", "/favicon.ico").permitAll()
                .requestMatchers("/users/**").hasAnyRole("SUPERADMIN", "ADMIN")
                .anyRequest().authenticated()
            )

            .formLogin(login -> login
                .loginPage("/login").permitAll()
                .loginProcessingUrl("/login")
                .usernameParameter("username")
                .passwordParameter("password")
                .defaultSuccessUrl("/", false)
                .failureUrl("/login?error") // útil para diagnosticar
            )

            .rememberMe(rm -> rm
                .key(keyRememberMe)
                .rememberMeParameter("remember-me")
                .rememberMeCookieName("IMPRIMELIBROS_REMEMBER")
                .tokenValiditySeconds(60 * 60 * 24 * 2)
                .userDetailsService(userDetailsService)
                .tokenRepository(tokenRepo)
            )

            .logout(logout -> logout
                .logoutUrl("/logout")
                .logoutSuccessUrl("/")
                .invalidateHttpSession(true)
                .deleteCookies("JSESSIONID", "IMPRIMELIBROS_REMEMBER")
                .permitAll()
            );

        return http.build();
    }
}
