package org.camunda.bpm.extension.commons.connector.support;

import com.google.gson.JsonObject;
import org.apache.commons.lang3.StringUtils;
import org.camunda.bpm.extension.commons.ro.req.IRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.ResponseEntity;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.util.UriBuilder;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;

import java.net.URI;
import java.util.Map;
import java.util.Properties;

import static org.springframework.security.oauth2.client.web.reactive.function.client.ServerOAuth2AuthorizedClientExchangeFilterFunction.clientRegistrationId;

@Service("bpmAccessHandler")
public class BPMAccessHandler extends AbstractAccessHandler{

    private static final Logger LOGGER = LoggerFactory.getLogger(BPMAccessHandler.class);
    private final Properties properties;
    private final WebClient webClient;

    public BPMAccessHandler(@Qualifier("integrationCredentialProperties") Properties integrationCredentialProperties, 
    		@Qualifier("unauthenticatedWebClient") WebClient unauthenticatedWebClient){
        this.properties = integrationCredentialProperties;
        this.webClient = unauthenticatedWebClient;
    }


    @Override
    public ResponseEntity<String> exchange(String url, HttpMethod method, Map<String, Object> queryParams, IRequest payload) {

        String host = getBpmHostAddress();

        ResponseEntity<String> response = webClient
                .method(method)
                .uri(host, builder -> buildQueryParams(builder, url, queryParams))
                .headers(h -> h.setBearerAuth(getUserBasedAccessToken()))
                .accept(MediaType.APPLICATION_JSON)
                .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
                .body((payload == null? BodyInserters.empty():BodyInserters.fromValue(payload)))
                .retrieve()
                .onStatus(HttpStatusCode::is4xxClientError,
                        clientResponse -> Mono.error(new HttpClientErrorException(clientResponse.statusCode())))
                .onStatus(HttpStatusCode::is5xxServerError,
                        clientResponse -> Mono.error(new HttpClientErrorException(clientResponse.statusCode())))
                .toEntity(String.class)
                .block();

        return new ResponseEntity<>(response.getBody(), response.getStatusCode());
    }

    private URI buildQueryParams(UriBuilder builder, String url, Map<String, Object> queryParams){

        String host = properties.getProperty("bpm.url");
        builder = builder.path(StringUtils.substringAfter(url, host));
        for(Map.Entry<String, Object> entry : queryParams.entrySet()){
            builder = builder.queryParam(entry.getKey(), entry.getValue());
        }
        return builder.build();
    }

    private String getBpmHostAddress(){
        String host = properties.getProperty("bpm.url");
        return StringUtils.substringBefore(host, "/engine-bpm");
    }
}
