package org.jboss.resteasy.test.providers.jettison;

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.logging.Logger;
import org.jboss.resteasy.annotations.providers.jaxb.json.Mapped;
import org.jboss.resteasy.client.jaxrs.ResteasyClient;
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
import org.jboss.resteasy.client.jaxrs.ResteasyWebTarget;
import org.jboss.resteasy.plugins.providers.jaxb.json.BadgerContext;
import org.jboss.resteasy.plugins.providers.jaxb.json.JettisonMappedContext;
import org.jboss.resteasy.test.providers.jettison.resource.Book;
import org.jboss.resteasy.test.providers.jettison.resource.BookStoreClient;
import org.jboss.resteasy.test.providers.jettison.resource.BookStoreResource;
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.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;

/**
 * @tpSubChapter Jettison provider
 * @tpChapter Integration tests
 * @tpSince RESTEasy 3.0.16
 */
@RunWith(Arquillian.class)
@RunAsClient
public class JaxbSmokeTest {

    private final Logger log = Logger.getLogger(JaxbSmokeTest.class.getName());
    private static ResteasyClient client;

    @Deployment
    public static Archive<?> deploy() {
        WebArchive war = TestUtil.prepareArchive(JaxbSmokeTest.class.getSimpleName());
        war.addClass(Book.class);
        return TestUtil.finishContainerPrepare(war, null, BookStoreResource.class);
    }

    @Before
    public void before() throws Exception {
        client = new ResteasyClientBuilder().build();
    }

    @After
    public void after() throws Exception {
        client.close();
        client = null;
    }

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

    @Test
    public void testNoDefaultsResource() {

        ResteasyWebTarget target = client.target(generateURL(""));
        BookStoreClient bookStoreClient = target.proxy(BookStoreClient.class);

        Book book = bookStoreClient.getBookByISBN("596529260");
        Assert.assertNotNull(book);
        Assert.assertEquals("RESTful Web Services", book.getTitle());

        book = new Book("Bill Burke", "666", "EJB 3.0");
        bookStoreClient.addBook(book);
        book = new Book("Bill Burke", "3434", "JBoss Workbook");
        bookStoreClient.addBookJson(book);

        book = bookStoreClient.getBookByISBN("666");
        Assert.assertEquals("Bill Burke", book.getAuthor());
        Assert.assertEquals("EJB 3.0", book.getTitle());

        book = bookStoreClient.getBookByISBNJson("3434");
        Assert.assertEquals("Bill Burke", book.getAuthor());
        Assert.assertEquals("JBoss Workbook", book.getTitle());

    }

    @XmlRootElement
    public static class Library {
        private String name;
        private List<Book> books;

        @XmlAttribute
        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        @XmlElement(name = "registered-books")
        public List<Book> getBooks() {
            return books;
        }

        public void setBooks(List<Book> books) {
            this.books = books;
        }
    }

    @Test
    @Mapped(attributesAsElements = {"title"})
    public void testJSON() throws Exception {
        {
            Mapped mapped = JaxbSmokeTest.class.getMethod("testJSON").getAnnotation(Mapped.class);
            JettisonMappedContext context = new JettisonMappedContext(mapped, Book.class);
            StringWriter writer = new StringWriter();
            context.createMarshaller().marshal(new Book("Bill Burke", "666", "EJB 3.0"), writer);

            String val = writer.toString();
            log.info("Mapped: " + val);

            // test Mapped attributeAsElement
            Assert.assertTrue(!val.contains("@title"));
        }
        {
            BadgerContext context = new BadgerContext(Book.class);
            StringWriter writer = new StringWriter();
            context.createMarshaller().marshal(new Book("Bill Burke", "666", "EJB 3.0"), writer);
            log.info("Badger: " + writer.toString());
        }
        Library library = new Library();
        List<Book> books = new ArrayList<>();
        books.add(new Book("Bill Burke", "555", "JBoss Workbook"));
        books.add(new Book("Bill Burke", "666", "EJB 3.0"));
        library.setName("BPL");
        library.setBooks(books);

        {
            BadgerContext context = new BadgerContext(Library.class);
            StringWriter writer = new StringWriter();
            context.createMarshaller().marshal(library, writer);

            String s = writer.toString();
            log.info("Badger: " + s);
            Library lib = (Library) context.createUnmarshaller().unmarshal(new StringReader(s));
            Assert.assertEquals(lib.getName(), "BPL");
            Assert.assertEquals(lib.getBooks().size(), 2);
        }
        {
            JettisonMappedContext context = new JettisonMappedContext(Library.class);
            StringWriter writer = new StringWriter();
            context.createMarshaller().marshal(library, writer);

            String s = writer.toString();
            log.info("Mapped: " + s);
            Library lib = (Library) context.createUnmarshaller().unmarshal(new StringReader(s));
            Assert.assertEquals(lib.getName(), "BPL");
            Assert.assertEquals(lib.getBooks().size(), 2);
        }
    }

}