package mx.gob.slp.baseadminweb.configuration.security;

import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.stereotype.Component;

@Component
@ConditionalOnProperty(prefix = "app.cognito", name = "enabled", havingValue = "true")
public class CognitoWebAuthenticationProvider implements AuthenticationProvider {

    private static final String ADMIN_ROLE = "ROLE_ADMIN";

    private final CognitoUserAuthenticator cognitoUserAuthenticator;
    private final CognitoProperties cognitoProperties;

    public CognitoWebAuthenticationProvider(CognitoUserAuthenticator cognitoUserAuthenticator,
                                            CognitoProperties cognitoProperties) {
        this.cognitoUserAuthenticator = cognitoUserAuthenticator;
        this.cognitoProperties = cognitoProperties;
    }

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        String username = authentication.getName();
        Object credentials = authentication.getCredentials();
        if (credentials == null) {
            throw new BadCredentialsException("La contrasena es obligatoria.");
        }

        CognitoUserAuthenticator.AuthenticationResult result = cognitoUserAuthenticator.authenticate(
                username,
                credentials.toString(),
                cognitoProperties.getAdminClientId(),
                ADMIN_ROLE
        );

        var authorities = result.roles().stream()
                .map(SimpleGrantedAuthority::new)
                .toList();

        String displayName = CognitoDisplayNameResolver.resolve(
                result.tokens().idToken(),
                result.tokens().accessToken(),
                result.username()
        );

        return UsernamePasswordAuthenticationToken.authenticated(
                new AuthenticatedWebUser(result.username(), displayName),
                null,
                authorities
        );
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication);
    }
}