package cz.moneta.test.harness.endpoints.wso2;

import cz.moneta.test.harness.connectors.rest.ExtendedRestConnector;
import cz.moneta.test.harness.connectors.rest.ExtendedRestResponse;
import cz.moneta.test.harness.connectors.rest.ResponseHandler;
import cz.moneta.test.harness.connectors.rest.RestConnector;
import cz.moneta.test.harness.connectors.wso2.RemoteWso2Connector;
import cz.moneta.test.harness.constants.HarnessConfigConstants;
import cz.moneta.test.harness.context.StoreAccessor;
import cz.moneta.test.harness.endpoints.RestEndpoint;
import cz.moneta.test.harness.performance.PerformanceWrapper;
import cz.moneta.test.harness.support.auth.AuthSupport;
import org.apache.commons.lang3.tuple.Pair;

import jakarta.ws.rs.client.Entity;
import jakarta.ws.rs.client.Invocation;
import jakarta.ws.rs.core.GenericType;
import jakarta.ws.rs.core.Response;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;

import static cz.moneta.test.harness.constants.HarnessConfigConstants.DEFAULT_REST_READ_TIMEOUT;

public class Wso2GatewayEndpoint implements RestEndpoint {

    private RestConnector restConnector;
    private StoreAccessor store;

    public Wso2GatewayEndpoint(StoreAccessor store) {
        this(store, DEFAULT_REST_READ_TIMEOUT);
    }

    @SuppressWarnings("unchecked")
    public Wso2GatewayEndpoint(StoreAccessor store, Long readTimeout) {
        this.store = store;
        restConnector = Optional.ofNullable(store.getConfig("endpoints.wso2.remote"))
                .map(Boolean::valueOf)
                .filter(t -> t)
                .<RestConnector>map(b -> new RemoteWso2Connector(store))
                .orElseGet(() -> Optional.ofNullable(store.getConfig("endpoints.wso2.gw.url"))
                        .map(url -> new ExtendedRestConnector(url, "Wso2GatewayLogger", readTimeout))
                        .map(c -> isPerformanceTest(store)
                                ? PerformanceWrapper.wrap(c, "wso2-performance-report.jtl", store, RestConnector.class)
                                : c)
                        .orElseThrow(() -> new IllegalStateException("You need to configure endpoints.wso2.gw.url to work with WSO2")));
    }

    @Override
    public <T> Pair<Integer, T> get(String path, Map<String, Object> properties, Class<T> responseType, Map<String, Object> headers) {
        return restConnector.get(path, properties, new GenericType<>(responseType), headers);
    }

    @Override
    public <T> Pair<Integer, T> post(String path, Entity<?> request, Class<T> responseType, Map<String, Object> headers, boolean rawResponse) {
        return restConnector.post(path, request, new GenericType<>(responseType), headers);
    }

   // @Override
    public <T> Pair<Integer, T> delete(String path, Map<String, Object> properties, Class<T> responseType, Map<String, Object> headers) {
        return restConnector.delete(path, properties, new GenericType<>(responseType), headers);
    }

    @Override
    public <T> Pair<Integer, T> patch(String path, Entity<?> request, Class<T> responseType, Map<String, Object> headers, boolean rawResponse) {
        return restConnector.patch(path, request, new GenericType<>(responseType), headers);
    }

    @Override
    public void close() {
        if (isPerformanceTest(store)) {
            restConnector.publishReport(store);
        }
    }

    private static boolean isPerformanceTest(StoreAccessor store) {
        return "true".equals(store.getConfig("performance.report.enable"));
    }

    /**
     * Return response body with response headers.
     */
    public <T> Pair<Integer, ExtendedRestResponse<T>> postExtended(String path, Entity<?> request,
                                                                   Class<T> responseType,
                                                                   Map<String, Object> headers) {
        return restConnector.postExtended(path, request, responseType, headers);
    }

    public Wso2GatewayEndpoint registerResponseHandler(ResponseHandler<
            Pair<Invocation.Builder, Function<Invocation.Builder, Response>>,
            Response> responseHandler) {
        restConnector.registerResponseHandler(responseHandler);
        return this;
    }

    public String getClientSecret(String clientKey) {
        return AuthSupport.getClientSecret(clientKey, store, HarnessConfigConstants.VAULT_WSO2_KEYS_PATH);
    }

    @Override
    public StoreAccessor getStore() {
        return store;
    }
}