package org.jboss.resteasy.test.providers;

import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.io.StringReader;
import java.io.StringWriter;
import java.net.URI;
import java.util.Date;

import javax.xml.parsers.DocumentBuilderFactory;

import jakarta.ws.rs.core.MediaType;
import jakarta.xml.bind.JAXBContext;
import jakarta.xml.bind.Marshaller;

import org.glassfish.jaxb.runtime.marshaller.NamespacePrefixMapper;
import org.jboss.logging.Logger;
import org.jboss.resteasy.plugins.providers.atom.Content;
import org.jboss.resteasy.plugins.providers.atom.Entry;
import org.jboss.resteasy.plugins.providers.atom.Feed;
import org.jboss.resteasy.plugins.providers.atom.Link;
import org.jboss.resteasy.plugins.providers.atom.Person;
import org.jboss.resteasy.plugins.providers.atom.Text;
import org.jboss.resteasy.test.providers.resource.AtomProviderModelCustomerAtom;
import org.junit.jupiter.api.Test;

/**
 * @tpSubChapter Providers
 * @tpChapter Unit tests
 * @tpTestCaseDetails Test for atom provider model
 * @tpSince RESTEasy 3.0.16
 */
public class AtomProviderModelTest {

    protected final Logger logger = Logger.getLogger(AtomProviderModelTest.class.getName());

    private static final String XML = "<content xmlns=\"http://www.w3.org/2005/Atom\" language=\"en\">Text\n" +
            "</content>";

    private static final String RFC_COMPLEX_XML = "   <feed xmlns=\"http://www.w3.org/2005/Atom\">\n" +
            "     <title type=\"text\">dive into mark</title>\n" +
            "     <subtitle type=\"html\">\n" +
            "       A &lt;em&gt;lot&lt;/em&gt; of effort\n" +
            "       went into making this effortless\n" +
            "     </subtitle>\n" +
            "     <updated>2005-07-31T12:29:29Z</updated>\n" +
            "     <id>tag:example.org,2003:3</id>\n" +
            "     <link rel=\"alternate\" type=\"text/html\"\n" +
            "      hreflang=\"en\" href=\"http://example.org/\"/>\n" +
            "     <link rel=\"self\" type=\"application/atom+xml\"\n" +
            "      href=\"http://example.org/feed.atom\"/>\n" +
            "     <rights>Copyright (c) 2003, Mark Pilgrim</rights>\n" +
            "     <generator uri=\"http://www.example.com/\" version=\"1.0\">\n" +
            "       Example Toolkit\n" +
            "     </generator>\n" +
            "     <entry>\n" +
            "       <title>Atom draft-07 snapshot</title>\n" +
            "       <link rel=\"alternate\" type=\"text/html\"\n" +
            "        href=\"http://example.org/2005/04/02/atom\"/>\n" +
            "       <link rel=\"enclosure\" type=\"audio/mpeg\" length=\"1337\"\n" +
            "        href=\"http://example.org/audio/ph34r_my_podcast.mp3\"/>\n" +
            "       <id>tag:example.org,2003:3.2397</id>\n" +
            "       <updated>2005-07-31T12:29:29Z</updated>\n" +
            "       <published>2003-12-13T08:29:29-04:00</published>\n" +
            "       <author>\n" +
            "         <name>Mark Pilgrim</name>\n" +
            "         <uri>http://example.org/</uri>\n" +
            "         <email>f8dy@example.com</email>\n" +
            "       </author>\n" +
            "       <contributor>\n" +
            "         <name>Sam Ruby</name>\n" +
            "       </contributor>\n" +
            "       <contributor>\n" +
            "         <name>Joe Gregorio</name>\n" +
            "       </contributor>\n" +
            "       <content type=\"xhtml\" xml:lang=\"en\"\n" +
            "        xml:base=\"http://diveintomark.org/\">\n" +
            "         <div xmlns=\"http://www.w3.org/1999/xhtml\">\n" +
            "           <p><i>[Update: The Atom draft is finished.]</i></p>\n" +
            "         </div>\n" +
            "       </content>\n" +
            "     </entry>\n" +
            "   </feed>";

    private static final NamespacePrefixMapper PREFIX_MAPPER = new NamespacePrefixMapper() {
        @Override
        public String getPreferredPrefix(final String namespaceUri, final String suggestion, final boolean requirePrefix) {
            if ("http://www.w3.org/2005/Atom".equals(namespaceUri)) {
                return "atom";
            }
            return suggestion;
        }
    };

    /**
     * @tpTestDetails Test JAXB content - text form
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void testContentText() throws Exception {
        JAXBContext ctx = JAXBContext.newInstance(Content.class);
        Content content = (Content) ctx.createUnmarshaller().unmarshal(new StringReader(XML));
        logger.info(content.getText());
        logger.info(content.getLanguage());

    }

    /**
     * @tpTestDetails Regression test for RESTEASY-242
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void testContentSetElement() throws Exception {
        Content c = new Content();
        c.setElement(DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument().createElement("Test"));
    }

    /**
     * @tpTestDetails Check JAXB content
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void testContent() throws Exception {

        Content content = new Content();
        content.setJAXBObject(new AtomProviderModelCustomerAtom("bill"));
        JAXBContext ctx = JAXBContext.newInstance(Content.class, AtomProviderModelCustomerAtom.class);

        Marshaller marshaller = ctx.createMarshaller();

        marshaller.setProperty("org.glassfish.jaxb.indentString", "   ");
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
        StringWriter writer = new StringWriter();

        marshaller.setProperty("org.glassfish.jaxb.namespacePrefixMapper", PREFIX_MAPPER);
        marshaller.marshal(content, writer);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        PrintStream ps = new PrintStream(baos);
        marshaller.marshal(content, ps);
        if (logger.isDebugEnabled()) {
            logger.debug("Result: " + ps.toString());

            logger.debug("**********");
            logger.debug(writer.toString());
        }
        content = (Content) ctx.createUnmarshaller().unmarshal(new StringReader(writer.toString()));

        AtomProviderModelCustomerAtom cust = content.getJAXBObject(AtomProviderModelCustomerAtom.class);
        logger.info(cust.getName());
    }

    /**
     * @tpTestDetails Check Atom Provider Binding
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void testBinding() throws Exception {
        Feed feed = new Feed();
        feed.setId(new URI("http://example.com/42"));
        feed.setTitle("Yo");
        feed.setUpdated(new Date());
        Link link = new Link();
        link.setHref(new URI("http://localhost"));
        link.setRel("edit");
        feed.getLinks().add(link);
        feed.getAuthors().add(new Person("Bill Burke"));

        Entry entry = new Entry();
        Text summary = new Text("<h1>Ho ho ho</h1>", "html");
        entry.setSummaryElement(summary);

        Text rights = new Text("(c) no rights");
        entry.setRightsElement(rights);

        entry.setTitle("<p>This is the <i>title</i></p>");
        entry.getTitleElement().setType(MediaType.APPLICATION_XHTML_XML_TYPE);

        feed.getEntries().add(entry);

        JAXBContext ctx = JAXBContext.newInstance(Feed.class);

        Marshaller marshaller = ctx.createMarshaller();
        marshaller.setProperty("org.glassfish.jaxb.namespacePrefixMapper", PREFIX_MAPPER);
        marshaller.setProperty("org.glassfish.jaxb.indentString", "   ");
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);

        StringWriter writer = new StringWriter();

        marshaller.marshal(feed, writer);

        feed = (Feed) ctx.createUnmarshaller().unmarshal(new StringReader(writer.toString()));

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        PrintStream ps = new PrintStream(baos);
        marshaller.marshal(feed, ps);
        logger.info("Result: " + ps.toString());
    }

    /**
     * @tpTestDetails Check RFC
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void testRFC() throws Exception {
        JAXBContext ctx = JAXBContext.newInstance(Feed.class);
        Feed feed = (Feed) ctx.createUnmarshaller().unmarshal(new StringReader(RFC_COMPLEX_XML));
        Marshaller marshaller = ctx.createMarshaller();

        marshaller.setProperty("org.glassfish.jaxb.indentString", "   ");
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        PrintStream ps = new PrintStream(baos);
        marshaller.marshal(feed, ps);
        logger.info("Result: " + ps.toString());
    }
}
