package es.uv.garcosda.gateway.security;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.reactive.function.client.WebClientResponseException;

import com.google.common.net.HttpHeaders;

import reactor.core.publisher.Mono;

@Component
public class AuthFilter extends AbstractGatewayFilterFactory<AuthFilter.Config> {
	
	@Autowired
	private WebClient.Builder client;
	
	public AuthFilter() {
        super(Config.class);
    }
	
	@Override
	public GatewayFilter apply(Config config) {
		
		return (exchange, chain) -> {
			
			ServerHttpResponse response = exchange.getResponse();
			
			if(!exchange.getRequest().getHeaders().containsKey(HttpHeaders.AUTHORIZATION)) {
				response.setStatusCode(HttpStatus.UNAUTHORIZED);
				return response.setComplete();
			}
			
			String authHeader = exchange.getRequest().getHeaders().get(HttpHeaders.AUTHORIZATION).get(0);
			if(!authHeader.contains("Bearer")) {
				response.setStatusCode(HttpStatus.UNAUTHORIZED);
				return response.setComplete();
			}
						
			         
			try {
				return client.build()
					         .get()
					         .uri("http://auth-service/auth/authorize")
					         .header(HttpHeaders.AUTHORIZATION, authHeader)
					         .retrieve()
					         .onStatus(httpStatus -> httpStatus.value() != HttpStatus.ACCEPTED.value(),
					        	 error -> { return Mono.error(new Throwable("UNAUTHORIZED")); })
					         .toEntity(String.class)
					         .flatMap(entity -> {	    	 
					       	     if(entity.getStatusCode().equals(HttpStatus.UNAUTHORIZED)) {
					    	 	     response.setStatusCode(HttpStatus.UNAUTHORIZED);
					    	 	     return response.setComplete();
					    	     }	 
					    	     return chain.filter(exchange);
					         });
			}
			catch (Throwable e){
				response.setStatusCode(HttpStatus.UNAUTHORIZED);
				return response.setComplete();
			}
		};

	}
	
	public static class Config{ }
	
}
