package org.jboss.resteasy.test.resource.param;

import jakarta.ws.rs.client.ClientBuilder;
import jakarta.ws.rs.core.Response;

import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.container.test.api.RunAsClient;
import org.jboss.arquillian.junit5.ArquillianExtension;
import org.jboss.resteasy.client.jaxrs.ResteasyClient;
import org.jboss.resteasy.spi.HttpResponseCodes;
import org.jboss.resteasy.test.resource.param.resource.MatrixParamAsPrimitiveArray;
import org.jboss.resteasy.test.resource.param.resource.MatrixParamAsPrimitiveArrayDefault;
import org.jboss.resteasy.test.resource.param.resource.MatrixParamAsPrimitiveArrayDefaultNull;
import org.jboss.resteasy.test.resource.param.resource.MatrixParamAsPrimitiveArrayDefaultOverride;
import org.jboss.resteasy.test.resource.param.resource.MatrixParamAsPrimitiveDefault;
import org.jboss.resteasy.test.resource.param.resource.MatrixParamAsPrimitiveDefaultNull;
import org.jboss.resteasy.test.resource.param.resource.MatrixParamAsPrimitiveDefaultOverride;
import org.jboss.resteasy.test.resource.param.resource.MatrixParamAsPrimitiveList;
import org.jboss.resteasy.test.resource.param.resource.MatrixParamAsPrimitiveListDefault;
import org.jboss.resteasy.test.resource.param.resource.MatrixParamAsPrimitiveListDefaultNull;
import org.jboss.resteasy.test.resource.param.resource.MatrixParamAsPrimitiveListDefaultOverride;
import org.jboss.resteasy.test.resource.param.resource.MatrixParamAsPrimitivePrimitives;
import org.jboss.resteasy.test.resource.param.resource.MatrixParamAsPrimitiveWrappers;
import org.jboss.resteasy.test.resource.param.resource.MatrixParamAsPrimitiveWrappersDefault;
import org.jboss.resteasy.test.resource.param.resource.MatrixParamAsPrimitiveWrappersDefaultNull;
import org.jboss.resteasy.test.resource.param.resource.MatrixParamAsPrimitiveWrappersDefaultOverride;
import org.jboss.resteasy.util.HttpHeaderNames;
import org.jboss.resteasy.utils.PortProviderUtil;
import org.jboss.resteasy.utils.TestUtil;
import org.jboss.shrinkwrap.api.Archive;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;

/**
 * @tpSubChapter Parameters
 * @tpChapter Integration tests
 * @tpTestCaseDetails Test all variants of primitive matrix parameters (boolean, int, long, float, etc.)
 * @tpSince RESTEasy 3.0.16
 */
@ExtendWith(ArquillianExtension.class)
@RunAsClient
public class MatrixParamAsPrimitiveTest {

    public static final String ERROR_MESSAGE = "Wrong content of matrix parameter";

    ResteasyClient client;

    @Deployment
    public static Archive<?> deploy() {
        WebArchive war = TestUtil.prepareArchive(MatrixParamAsPrimitiveTest.class.getSimpleName());
        war.addClass(MatrixParamAsPrimitiveTest.class);
        return TestUtil.finishContainerPrepare(war, null,
                MatrixParamAsPrimitivePrimitives.class,
                MatrixParamAsPrimitiveDefault.class,
                MatrixParamAsPrimitiveDefaultOverride.class,
                MatrixParamAsPrimitiveDefaultNull.class,
                MatrixParamAsPrimitiveWrappers.class,
                MatrixParamAsPrimitiveWrappersDefault.class,
                MatrixParamAsPrimitiveWrappersDefaultNull.class,
                MatrixParamAsPrimitiveWrappersDefaultOverride.class,
                MatrixParamAsPrimitiveList.class,
                MatrixParamAsPrimitiveListDefault.class,
                MatrixParamAsPrimitiveListDefaultNull.class,
                MatrixParamAsPrimitiveListDefaultOverride.class,
                MatrixParamAsPrimitiveArray.class,
                MatrixParamAsPrimitiveArrayDefault.class,
                MatrixParamAsPrimitiveArrayDefaultNull.class,
                MatrixParamAsPrimitiveArrayDefaultOverride.class);
    }

    private String generateURL(String path) {
        return PortProviderUtil.generateURL(path, MatrixParamAsPrimitiveTest.class.getSimpleName());
    }

    public void basicTest(String type, String value) {
        String param = ";" + type + "=" + value;
        {
            client = (ResteasyClient) ClientBuilder.newClient();
            Response response = client.target(generateURL("/" + param)).request()
                    .header(HttpHeaderNames.ACCEPT, "application/" + type)
                    .get();
            Assertions.assertEquals(HttpResponseCodes.SC_OK, response.getStatus());
            response.close();
            client.close();
        }

        {
            client = (ResteasyClient) ClientBuilder.newClient();
            Response response = client.target(generateURL("/wrappers" + param)).request()
                    .header(HttpHeaderNames.ACCEPT, "application/" + type)
                    .get();
            Assertions.assertEquals(HttpResponseCodes.SC_OK, response.getStatus());
            response.close();
            client.close();
        }

        {
            client = (ResteasyClient) ClientBuilder.newClient();
            Response response = client.target(generateURL("/list" + param + param + param)).request()
                    .header(HttpHeaderNames.ACCEPT, "application/" + type)
                    .get();
            Assertions.assertEquals(HttpResponseCodes.SC_OK, response.getStatus());
            response.close();
            client.close();
        }

        {
            client = (ResteasyClient) ClientBuilder.newClient();
            Response response = client.target(generateURL("/array" + param + param + param)).request()
                    .header(HttpHeaderNames.ACCEPT, "application/" + type)
                    .get();
            Assertions.assertEquals(HttpResponseCodes.SC_OK, response.getStatus());
            response.close();
            client.close();
        }
    }

    public void testDefault(String base, String type, String value) {
        {
            client = (ResteasyClient) ClientBuilder.newClient();
            Response response = client.target(generateURL(base + "default/null")).request()
                    .header(HttpHeaderNames.ACCEPT, "application/" + type)
                    .get();
            Assertions.assertEquals(HttpResponseCodes.SC_OK, response.getStatus());
            response.close();
            client.close();
        }

        {
            client = (ResteasyClient) ClientBuilder.newClient();
            Response response = client.target(generateURL(base + "default")).request()
                    .header(HttpHeaderNames.ACCEPT, "application/" + type)
                    .get();
            Assertions.assertEquals(HttpResponseCodes.SC_OK, response.getStatus());
            response.close();
            client.close();
        }

        String param = ";" + type + "=" + value;
        {
            client = (ResteasyClient) ClientBuilder.newClient();
            Response response = client.target(generateURL(base + "default/override" + param)).request()
                    .header(HttpHeaderNames.ACCEPT, "application/" + type)
                    .get();
            Assertions.assertEquals(HttpResponseCodes.SC_OK, response.getStatus());
            response.close();
            client.close();
        }
    }

    public void testDefault(String type, String value) {
        testDefault("/", type, value);
    }

    public void testWrappersDefault(String type, String value) {
        testDefault("/wrappers/", type, value);
    }

    public void testListDefault(String type, String value) {
        testDefault("/list/", type, value);
    }

    public void testArrayDefault(String type, String value) {
        testDefault("/array/", type, value);
    }

    /**
     * @tpTestDetails Basic test for boolean
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void testGetBoolean() {
        basicTest("boolean", "true");
    }

    /**
     * @tpTestDetails Test default value for boolean
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void testGetBooleanPrimitivesDefault() {
        testDefault("boolean", "true");
    }

    /**
     * @tpTestDetails Test default value of boolean with wrapper
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void testGetBooleanPrimitiveWrapperDefault() {
        testWrappersDefault("boolean", "true");
    }

    /**
     * @tpTestDetails Test default values of list of boolean
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void testGetBooleanPrimitiveListDefault() {
        testListDefault("boolean", "true");
        testArrayDefault("boolean", "true");
    }

    /**
     * @tpTestDetails Basic test for byte
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void testGetByte() {
        basicTest("byte", "127");
    }

    /**
     * @tpTestDetails Test default value of byte
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void testGetBytePrimitivesDefault() {
        testDefault("byte", "127");
    }

    /**
     * @tpTestDetails Test default value of byte with wrapper
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void testGetBytePrimitiveWrappersDefault() {
        testWrappersDefault("byte", "127");
    }

    /**
     * @tpTestDetails Test default value of list and array of byte
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void testGetBytePrimitiveListDefault() {
        testListDefault("byte", "127");
        testArrayDefault("byte", "127");
    }

    /**
     * @tpTestDetails Basic test for short
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void testGetShort() {
        basicTest("short", "32767");
    }

    /**
     * @tpTestDetails Test default values of short
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void testGetShortPrimtivesDefault() {
        testDefault("short", "32767");
    }

    /**
     * @tpTestDetails Test default values of short with wrapper
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void testGetShortPrimtiveWrappersDefault() {
        testWrappersDefault("short", "32767");
    }

    /**
     * @tpTestDetails Test default values of list and array of short
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void testGetShortPrimtiveListDefault() {
        testListDefault("short", "32767");
        testArrayDefault("short", "32767");
    }

    /**
     * @tpTestDetails Basic test for int
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void testGetInt() {
        basicTest("int", "2147483647");
    }

    /**
     * @tpTestDetails Test default value of int
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void testGetIntPrimitivesDefault() {
        testDefault("int", "2147483647");
    }

    /**
     * @tpTestDetails Test default value of int with wrapper
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void testGetIntPrimitiveWrappersDefault() {
        testWrappersDefault("int", "2147483647");
    }

    /**
     * @tpTestDetails Test default value of list and array of integer
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void testGetIntPrimitiveListDefault() {
        testListDefault("int", "2147483647");
        testArrayDefault("int", "2147483647");
    }

    /**
     * @tpTestDetails Basic test for long
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void testGetLong() {
        basicTest("long", "9223372036854775807");
    }

    /**
     * @tpTestDetails Test default value of long
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void testGetLongPrimitivesDefault() {
        testDefault("long", "9223372036854775807");
    }

    /**
     * @tpTestDetails Test default value of long with wrapper
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void testGetLongPrimitiveWrappersDefault() {
        testWrappersDefault("long", "9223372036854775807");
    }

    /**
     * @tpTestDetails Test default value of list and array of long
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void testGetLongPrimitiveListDefault() {
        testListDefault("long", "9223372036854775807");
        testArrayDefault("long", "9223372036854775807");
    }

    /**
     * @tpTestDetails Basic test for float
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void testGetFloat() {
        basicTest("float", "3.14159265");
    }

    /**
     * @tpTestDetails Test default value of float
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void testGetFloatPrimitivesDefault() {
        testDefault("float", "3.14159265");
    }

    /**
     * @tpTestDetails Test default value of float with wrapper
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void testGetFloatPrimitiveWrappersDefault() {
        testWrappersDefault("float", "3.14159265");
    }

    /**
     * @tpTestDetails Test default value of array and list of float
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void testGetFloatPrimitiveListDefault() {
        testListDefault("float", "3.14159265");
        testArrayDefault("float", "3.14159265");
    }

    /**
     * @tpTestDetails Basic test for double
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void testGetDouble() {
        basicTest("double", "3.14159265358979");
    }

    /**
     * @tpTestDetails Test default value of double
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void testGetDoublePrimitivesDefault() {
        testDefault("double", "3.14159265358979");
    }

    /**
     * @tpTestDetails Test default value of double with wrapper
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void testGetDoublePrimitiveWrappersDefault() {
        testWrappersDefault("double", "3.14159265358979");
    }

    /**
     * @tpTestDetails Test default value of list and array of double
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void testGetDoublePrimitiveListDefault() {
        testListDefault("double", "3.14159265358979");
        testArrayDefault("double", "3.14159265358979");
    }

    /**
     * @tpTestDetails Basic test for char
     * @tpSince RESTEasy 3.0.24
     */
    @Test
    public void testGetChar() {
        basicTest("char", "a");
    }

    /**
     * @tpTestDetails Test default value of char
     * @tpSince RESTEasy 3.0.24
     */
    @Test
    public void testGetCharPrimitivesDefault() {
        testDefault("char", "a");
    }

    /**
     * @tpTestDetails Test default value of char with wrapper
     * @tpSince RESTEasy 3.0.24
     */
    @Test
    public void testGetCharPrimitiveWrappersDefault() {
        testWrappersDefault("char", "a");
    }

    /**
     * @tpTestDetails Test default value of list and array of char
     * @tpSince RESTEasy 3.0.24
     */
    @Test
    public void testGetCharPrimitiveListDefault() {
        testListDefault("char", "a");
        testArrayDefault("char", "a");
    }

    /**
     * @tpTestDetails Test wrong data stored in int format
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void testBadPrimitiveValue() {
        {
            client = (ResteasyClient) ClientBuilder.newClient();
            Response response = client.target(generateURL("/;int=abcdef")).request()
                    .header(HttpHeaderNames.ACCEPT, "application/int")
                    .get();
            Assertions.assertEquals(HttpResponseCodes.SC_NOT_FOUND, response.getStatus());
            response.close();
            client.close();
        }
    }

    /**
     * @tpTestDetails Test wrong data stored in int format, wrapper is used
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void testBadPrimitiveWrapperValue() {
        {
            client = (ResteasyClient) ClientBuilder.newClient();
            Response response = client.target(generateURL("/wrappers;int=abcdef")).request()
                    .header(HttpHeaderNames.ACCEPT, "application/int")
                    .get();
            Assertions.assertEquals(HttpResponseCodes.SC_NOT_FOUND, response.getStatus());
            response.close();
            client.close();
        }
    }

    /**
     * @tpTestDetails Test wrong data stored in list of int
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void testBadPrimitiveListValue() {
        {
            client = (ResteasyClient) ClientBuilder.newClient();
            Response response = client.target(generateURL("/list;int=abcdef;int=abcdef")).request()
                    .header(HttpHeaderNames.ACCEPT, "application/int")
                    .get();
            Assertions.assertEquals(HttpResponseCodes.SC_NOT_FOUND, response.getStatus());
            response.close();
            client.close();
        }
    }
}
