package com.wishurgift.entry.security;

import com.wishurgift.utils.Constant;
import com.wishurgift.utils.JwtUtils;
import com.wishurgift.wrapper.Result;
import lombok.extern.slf4j.Slf4j;

import javax.annotation.Priority;
import javax.ws.rs.Priorities;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.ext.Provider;
import java.security.Principal;

import static com.wishurgift.utils.Constant.AUTHENTICATION_SCHEME;

@Slf4j
@Secured
@Provider
@Priority(Priorities.AUTHENTICATION)
public class SecuredAuthenticationFilter implements ContainerRequestFilter {

    @Override
    public void filter(ContainerRequestContext requestContext) {
        log.info("Enter in SecuredAuthenticationFilter");
        // Recupération du header
        String authorizationHeader = requestContext.getHeaderString(HttpHeaders.AUTHORIZATION);
        if (authorizationHeader == null) {
            log.info("Authorization header not found");
            abort(requestContext, "Authorization header not found");
            return;
        }

        // Validation du header
        if (!JwtUtils.isTokenAuthentication(authorizationHeader)) {
            log.info("Invalid Authorization header");
            abort(requestContext, "Invalid Authorization header");
            return;
        }

        // Extraction du token
        String token = authorizationHeader.substring(AUTHENTICATION_SCHEME.length()).trim();

        // Verification du token
        if (!JwtUtils.verify(token)) {
            log.info("JWT authentication token is invalid");
            abort(requestContext, "JWT authentication token is invalid");
            return;
        }
        log.info("User connected, token: {}", token.split("\\.")[1]);

        // Definition de contexte de securité
        final SecurityContext currentSecurityContext = requestContext.getSecurityContext();
        requestContext.setSecurityContext(new SecurityContext() {

            @Override
            public Principal getUserPrincipal() {
                return () -> token;
            }

            @Override
            public boolean isUserInRole(String role) {
                return true;
            }

            @Override
            public boolean isSecure() {
                return currentSecurityContext.isSecure();
            }

            @Override
            public String getAuthenticationScheme() {
                return AUTHENTICATION_SCHEME;
            }
        });
    }

    /**
     * Met fin à la connexion, avec une erreur acces non autorisé
     *
     * @param requestContext
     */
    private void abort(ContainerRequestContext requestContext, String trace) {
        requestContext.abortWith(
                Response.status(Response.Status.UNAUTHORIZED)
                        .header(HttpHeaders.WWW_AUTHENTICATE, AUTHENTICATION_SCHEME + " realm=\"" + Constant.AUTHENTICATION_REALM + "\"")
                        .entity(Result.error().data(Result.Error.UNAUTHORIZED).trace(trace).build())
                        .type(MediaType.APPLICATION_JSON_TYPE)
                        .build());
    }

}
