package com.ease.gsms.server.controllers.filters;

import com.ease.gsms.server.repositories.ApiKeyRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.AuthenticationManager;
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.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.RequestHeaderRequestMatcher;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.security.Principal;
import java.util.Collection;
import java.util.UUID;

public class ApiKeyAuthenticationFilter extends AbstractAuthenticationProcessingFilter {

    private Logger logger = LoggerFactory.getLogger(ApiKeyAuthenticationFilter.class);

    private ApiKeyRepository apiKeyRepository;

    private AuthenticationManager authenticationManager;

    private UserDetailsService userDetailsService;

    public ApiKeyAuthenticationFilter(AuthenticationManager authenticationManager, ApiKeyRepository apiKeyRepository, UserDetailsService userDetailsService) {
        super(new RequestHeaderRequestMatcher("X-Api-Key"));
        setAuthenticationManager(this.authenticationManager = authenticationManager);
        this.apiKeyRepository = apiKeyRepository;
        this.userDetailsService = userDetailsService;
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {

        String apiKeyHeader = request.getHeader("X-Api-Key");

        UUID apiKey;

        try {
            apiKey = UUID.fromString(apiKeyHeader);
        } catch (Exception e) {
            throw new BadCredentialsException("Wrong api key format");
        }

        String userName = apiKeyRepository.getUsernameByApiKey(apiKey);

        if (userName == null) {
            throw new BadCredentialsException(
                    String.format(
                            "Unknown api key: %s",
                            apiKey
                    )
            );
        }

        UserDetails userDetails = userDetailsService.loadUserByUsername(userName);

        Collection<? extends GrantedAuthority> authorities = userDetails.getAuthorities();

        return getAuthenticationManager().authenticate(
                new ApiKeyAuthenticationToken(userDetails, apiKey, authorities)
        );

    }

    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
//        super.successfulAuthentication(request, response, chain, authResult);
        SecurityContextHolder.getContext().setAuthentication(authResult);
        chain.doFilter(request, response);
    }
}