package stirling.software.SPDF.config.security;

import java.io.IOException;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Lazy;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import stirling.software.SPDF.model.ApiKeyAuthenticationToken;
@Component
public class UserAuthenticationFilter extends OncePerRequestFilter {

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    @Lazy
    private UserService userService;
    
   
    @Autowired
    @Qualifier("loginEnabled")
    public boolean loginEnabledValue;

    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain filterChain) throws ServletException, IOException {

        if (!loginEnabledValue) {
            // If login is not enabled, just pass all requests without authentication
            filterChain.doFilter(request, response);
            return;
        }
        String requestURI = request.getRequestURI(); 
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

        // Check for API key in the request headers if no authentication exists
        if (authentication == null || !authentication.isAuthenticated()) {
            String apiKey = request.getHeader("X-API-Key");
            if (apiKey != null && !apiKey.trim().isEmpty()) {
                try {
                    // Use API key to authenticate. This requires you to have an authentication provider for API keys.
                	UserDetails userDetails = userService.loadUserByApiKey(apiKey);
                	if(userDetails == null)
                	{
                		response.setStatus(HttpStatus.UNAUTHORIZED.value());
                        response.getWriter().write("Invalid API Key.");
                        return;
                	}
                    authentication = new ApiKeyAuthenticationToken(userDetails, apiKey, userDetails.getAuthorities());
                    SecurityContextHolder.getContext().setAuthentication(authentication);
                } catch (AuthenticationException e) {
                    // If API key authentication fails, deny the request
                    response.setStatus(HttpStatus.UNAUTHORIZED.value());
                    response.getWriter().write("Invalid API Key.");
                    return;
                }
            }
        }

        // If we still don't have any authentication, deny the request
        if (authentication == null || !authentication.isAuthenticated()) {
        	String method = request.getMethod();
        	String contextPath = request.getContextPath();
        	
        	if ("GET".equalsIgnoreCase(method) && !  (contextPath + "/login").equals(requestURI)) {
        		 response.sendRedirect(contextPath + "/login");  // redirect to the login page
        	     return;
            } else {
	            response.setStatus(HttpStatus.UNAUTHORIZED.value());
	            response.getWriter().write("Authentication required. Please provide a X-API-KEY in request header.\nThis is found in Settings -> Account Settings -> API Key\nAlternativly you can disable authentication if this is unexpected");
	            return;
            }
        } 

        filterChain.doFilter(request, response);
    }
    
    @Override
    protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
        String uri = request.getRequestURI();
        String contextPath = request.getContextPath();
        String[] permitAllPatterns = {
        		contextPath + "/login",
        		contextPath + "/register",
        		contextPath + "/error",
        		contextPath + "/images/",
        		contextPath + "/public/",
        		contextPath + "/css/",
        		contextPath + "/js/",
        		contextPath +  "/pdfjs/",
        		contextPath +  "/site.webmanifest"
        };

        for (String pattern : permitAllPatterns) {
            if (uri.startsWith(pattern) || uri.endsWith(".svg")) {
                return true;
            }
        }

        return false;
    }

}
