package mesosphere.dcos.client;

import feign.Feign;
import feign.Response;
import feign.codec.ErrorDecoder;
import feign.gson.GsonDecoder;
import feign.gson.GsonEncoder;
import mesosphere.client.common.ModelUtils;
import mesosphere.dcos.client.model.DCOSAuthCredentials;

import org.apache.commons.io.IOUtils;

import java.io.IOException;
import java.util.function.Consumer;

public class DCOSClient {
    public static DCOS getInstance(String endpoint) {
        return buildInstance(endpoint, b -> {});
    }

    public static DCOS getInstance(String endpoint, final DCOSAuthCredentials authCredentials) {
        // Need to use a non-authenticated DCOSClient instance to perform the authorization and token refresh to avoid
        // the complexity of synchronizing around checking whether a token needs to be refreshed.
        return buildInstance(endpoint, b ->
                b.requestInterceptor(new DCOSAuthTokenHeaderInterceptor(authCredentials, getInstance(endpoint))));
    }

    private static DCOS buildInstance(String endpoint, Consumer<Feign.Builder> customize) {
        GsonDecoder decoder = new GsonDecoder(ModelUtils.GSON);
        GsonEncoder encoder = new GsonEncoder(ModelUtils.GSON);

        Feign.Builder builder = Feign.builder()
                                     .encoder(encoder)
                                     .decoder(decoder)
                                     .errorDecoder(new DCOSErrorDecoder());
        customize.accept(builder);
        builder.requestInterceptor(new DCOSAPIInterceptor());

        return builder.target(DCOS.class, endpoint);
    }

    private static class DCOSErrorDecoder implements ErrorDecoder {
        @Override
        public Exception decode(String methodKey, Response response) {

            String details;
            try {
                details = IOUtils.toString(response.body().asInputStream(), "UTF-8");
            } catch (NullPointerException | IOException e) {
                details = "Unable to read response body";
            }
            return new DCOSException(response.status(), response.reason(), methodKey, details);
        }
    }
}