package dev.ai4j.openai4j;

import okhttp3.OkHttpClient;
import retrofit2.Call;

import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;

class RequestExecutor<Request, Response, ResponseContent>
        implements SyncOrAsyncOrStreaming<ResponseContent> {

    private final Call<Response> call;
    private final Function<Response, ResponseContent> responseContentExtractor;

    private final OkHttpClient okHttpClient;
    private final String endpointUrl;
    private final Supplier<Request> requestWithStreamSupplier;
    private final Class<Response> responseClass;
    private final Function<Response, ResponseContent> streamEventContentExtractor;
    private final boolean logStreamingResponses;

    RequestExecutor(Call<Response> call,
                    Function<Response, ResponseContent> responseContentExtractor,

                    OkHttpClient okHttpClient,
                    String endpointUrl,
                    Supplier<Request> requestWithStreamSupplier,
                    Class<Response> responseClass,
                    Function<Response, ResponseContent> streamEventContentExtractor,
                    boolean logStreamingResponses
    ) {
        this.call = call;
        this.responseContentExtractor = responseContentExtractor;

        this.okHttpClient = okHttpClient;
        this.endpointUrl = endpointUrl;
        this.requestWithStreamSupplier = requestWithStreamSupplier;
        this.responseClass = responseClass;
        this.streamEventContentExtractor = streamEventContentExtractor;
        this.logStreamingResponses = logStreamingResponses;
    }

    RequestExecutor(Call<Response> call, Function<Response, ResponseContent> responseContentExtractor) {
        this.call = call;
        this.responseContentExtractor = responseContentExtractor;

        this.okHttpClient = null;
        this.endpointUrl = null;
        this.requestWithStreamSupplier = null;
        this.responseClass = null;
        this.streamEventContentExtractor = null;
        this.logStreamingResponses = false;
    }

    @Override
    public ResponseContent execute() {

        return new SyncRequestExecutor<>(call, responseContentExtractor).execute();
    }

    @Override
    public AsyncResponseHandling onResponse(Consumer<ResponseContent> responseHandler) {

        return new AsyncRequestExecutor<>(call, responseContentExtractor).onResponse(responseHandler);
    }

    @Override
    public StreamingResponseHandling onPartialResponse(Consumer<ResponseContent> partialResponseHandler) {

        return new StreamingRequestExecutor<>(
                okHttpClient,
                endpointUrl,
                requestWithStreamSupplier,
                responseClass,
                streamEventContentExtractor,
                logStreamingResponses
        ).onPartialResponse(partialResponseHandler);
    }
}