package com.cameleer.server.app.http;

import com.cameleer.server.core.http.OutboundHttpProperties;
import com.cameleer.server.core.http.OutboundHttpRequestContext;
import com.cameleer.server.core.http.TrustMode;
import com.github.tomakehurst.wiremock.WireMockServer;
import com.github.tomakehurst.wiremock.core.WireMockConfiguration;
import org.apache.hc.client5.http.classic.methods.HttpGet;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.core5.http.io.entity.EntityUtils;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.time.Duration;
import java.util.List;

import static com.github.tomakehurst.wiremock.client.WireMock.*;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;

class ApacheOutboundHttpClientFactoryIT {

    private WireMockServer wm;
    private ApacheOutboundHttpClientFactory factory;

    @BeforeEach
    void setUp() {
        wm = new WireMockServer(WireMockConfiguration.options()
                .httpDisabled(true).dynamicHttpsPort());
        wm.start();
        wm.stubFor(get("/ping").willReturn(ok("pong")));

        OutboundHttpProperties props = new OutboundHttpProperties(
                false, List.of(), Duration.ofSeconds(2), Duration.ofSeconds(5), null, null, null);
        factory = new ApacheOutboundHttpClientFactory(props, new SslContextBuilder());
    }

    @AfterEach
    void tearDown() {
        if (wm != null) wm.stop();
    }

    @Test
    void trustAllBypassesWiremockSelfSignedCert() throws Exception {
        CloseableHttpClient client = factory.clientFor(
                new OutboundHttpRequestContext(TrustMode.TRUST_ALL, List.of(), null, null));
        try (var resp = client.execute(new HttpGet("https://localhost:" + wm.httpsPort() + "/ping"))) {
            assertThat(resp.getCode()).isEqualTo(200);
            assertThat(EntityUtils.toString(resp.getEntity())).isEqualTo("pong");
        }
    }

    @Test
    void systemDefaultRejectsSelfSignedCert() {
        CloseableHttpClient client = factory.clientFor(OutboundHttpRequestContext.systemDefault());
        assertThatThrownBy(() -> client.execute(new HttpGet("https://localhost:" + wm.httpsPort() + "/ping")))
                .isInstanceOfAny(javax.net.ssl.SSLException.class, javax.net.ssl.SSLHandshakeException.class);
    }

    @Test
    void clientsAreMemoizedByContext() {
        CloseableHttpClient c1 = factory.clientFor(OutboundHttpRequestContext.systemDefault());
        CloseableHttpClient c2 = factory.clientFor(OutboundHttpRequestContext.systemDefault());
        assertThat(c1).isSameAs(c2);
    }
}
