package org.jboss.resteasy.test.response;

import java.lang.reflect.ReflectPermission;
import java.util.Map;
import java.util.PropertyPermission;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Invocation;
import javax.ws.rs.core.Cookie;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.NewCookie;
import javax.ws.rs.core.Response;

import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.container.test.api.RunAsClient;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.resteasy.utils.PermissionUtil;
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.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;

@RunWith(Arquillian.class)
@RunAsClient
public class CommitNewCookiesHeaderTest {

   @Path("echo")
   public static class EchoResource {

      @Produces(MediaType.TEXT_PLAIN)
      @GET
      public Response echo(@QueryParam("msg") String msg) {
         // send cookie as a simple string
         return Response.ok(msg).header(HttpHeaders.SET_COOKIE, "Cookie 1=Cookie 1 value;Version=1;Path=/")
                 .cookie(new NewCookie("Cookie 2", "Cookie 2 value"),
                         new NewCookie("Cookie 3", "Cookie 3 value"))
                 .build();
      }

      @Path("two")
      @Produces(MediaType.TEXT_PLAIN)
      @GET
      public Response echoTwo(@QueryParam("msg") String msg) {
         // Any class that provides a toString can be provided as a cookie
         return Response.ok().header(HttpHeaders.SET_COOKIE,
                 new Object() {
                     @Override
                     public String toString() {
                        return "Cookie 1=Cookie 1 value;Version=1;Path=/";
                     }
                  })
         .cookie(new NewCookie("Cookie 2", "Cookie 2 value"))
         .build();
      }

      @Path("three")
      @Produces(MediaType.TEXT_PLAIN)
      @GET
      public Response echoThree(@QueryParam("msg") String msg) {
         // Cookie should really only be used with request but it is an object with a toString impl
         return Response.ok(msg).header(HttpHeaders.SET_COOKIE,  new Cookie("Cookie 1", "Cookie 1 value"))
                 .cookie(new NewCookie("Cookie 2", "Cookie 2 value"))
                 .build();
      }

   }

   private static Client client;
   private static final String DEP = "CommitCookiesHeaderTest";

   @Deployment
   public static Archive<?> deploy() {
      WebArchive war = TestUtil.prepareArchive(DEP);
      war.addClass(EchoResource.class);
      war.addAsManifestResource(PermissionUtil.createPermissionsXmlAsset(
            new ReflectPermission("suppressAccessChecks"),
            new PropertyPermission("ipv6", "read"),
            new PropertyPermission("node", "read")
      ), "permissions.xml");
      return TestUtil.finishContainerPrepare(war, null, EchoResource.class);
   }

   @BeforeClass
   public static void setup() {
      client = ClientBuilder.newClient();
   }

   @AfterClass
   public static void cleanup() {
      client.close();
   }

   private String generateURL() {
      return PortProviderUtil.generateBaseUrl(DEP);
   }

   @Test
   public void testAcceptApplicationStar() throws Exception {
      Invocation.Builder request = client.target(generateURL()).path("echo").queryParam("msg", "Hello world")
            .request(MediaType.TEXT_PLAIN_TYPE);
      try (Response response = request.get()) {
         Map<String, NewCookie> cookies = response.getCookies();
         Assert.assertEquals(3, cookies.size());
         Assert.assertEquals("Cookie 1 value", cookies.get("Cookie 1").getValue());
         Assert.assertEquals("Cookie 2 value", cookies.get("Cookie 2").getValue());
         Assert.assertEquals("Cookie 3 value", cookies.get("Cookie 3").getValue());
      }
   }

   @Test
   public void testSecondCase() throws Exception {
      Invocation.Builder request = client.target(generateURL()).path("echo/two").queryParam("msg", "Hello world")
            .request(MediaType.TEXT_PLAIN_TYPE);
      try (Response response = request.get()) {
         Map<String, NewCookie> cookies = response.getCookies();
         Assert.assertEquals(2, cookies.size());
         Assert.assertEquals("Cookie 1 value", cookies.get("Cookie 1").getValue());
         Assert.assertEquals("Cookie 2 value", cookies.get("Cookie 2").getValue());
      }
   }

   @Test
   public void testThreeCase() throws Exception {
      Invocation.Builder request = client.target(generateURL()).path("echo/three").queryParam("msg", "Hello world")
            .request(MediaType.TEXT_PLAIN_TYPE);
      try (Response response = request.get()) {
         Map<String, NewCookie> cookies = response.getCookies();
         Assert.assertEquals(2, cookies.size());
         Assert.assertEquals("Cookie 1 value", cookies.get("Cookie 1").getValue());
         Assert.assertEquals("Cookie 2 value", cookies.get("Cookie 2").getValue());
      }
   }
}
