//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//

package org.eclipse.jetty.ee9.quickstart;

import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;

import org.eclipse.jetty.ee9.annotations.AnnotationConfiguration;
import org.eclipse.jetty.ee9.plus.webapp.EnvConfiguration;
import org.eclipse.jetty.ee9.plus.webapp.PlusConfiguration;
import org.eclipse.jetty.ee9.webapp.WebAppContext;
import org.eclipse.jetty.ee9.webapp.WebDescriptor;
import org.eclipse.jetty.server.NetworkConnector;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.toolchain.test.FS;
import org.eclipse.jetty.toolchain.test.MavenPaths;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.xml.XmlConfiguration;
import org.eclipse.jetty.xml.XmlParser.Node;
import org.hamcrest.Matchers;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;

public class QuickStartTest
{
    /**
     * Test of an exploded webapp directory, no WEB-INF/quickstart-web.xml,
     * with QuickStartConfiguration enabled.
     */
    @ParameterizedTest
    @ValueSource(booleans = {true, false})
    public void testExplodedWebAppDirNoWebXml(boolean defaultMode) throws Exception
    {
        Path jettyHome = MavenPaths.targetDir();
        Path webappDir = MavenPaths.targetTestDir("no-web-xml");
        Path src = MavenPaths.projectBase().resolve("src/test/webapps/no-web-xml");
        FS.ensureEmpty(webappDir);
        org.eclipse.jetty.toolchain.test.IO.copyDir(src, webappDir);

        System.setProperty("jetty.home", jettyHome.toString());

        Server server = new Server(0);

        WebAppContext webapp = new WebAppContext();
        webapp.addConfiguration(new QuickStartConfiguration(),
            new EnvConfiguration(),
            new PlusConfiguration(),
            new AnnotationConfiguration());
        // Default mode should allow this style of exploded webapp dir.
        if (!defaultMode)
            webapp.setAttribute(QuickStartConfiguration.MODE, QuickStartConfiguration.Mode.AUTO);

        Resource warResource = webapp.getResourceFactory().newResource(webappDir);
        webapp.setWarResource(warResource);
        webapp.setContextPath("/");
        server.setHandler(webapp);
        server.start();

        URL url = new URL("http://127.0.0.1:" + server.getBean(NetworkConnector.class).getLocalPort() + "/index.html");
        HttpURLConnection connection = (HttpURLConnection)url.openConnection();
        assertEquals(200, connection.getResponseCode());
        assertThat(IO.toString((InputStream)connection.getContent()), Matchers.containsString("<p>Contents of no-web-xml</p>"));

        server.stop();
    }

    @Test
    public void testStandardTestWar() throws Exception
    {
        WebAppContext webapp = new WebAppContext();

        //Generate the quickstart
        PreconfigureStandardTestWar.main(new String[]{});

        Path workDir = MavenPaths.targetTestDir(PreconfigureStandardTestWar.class.getSimpleName());
        Path targetDir = workDir.resolve("test-standard-preconfigured");

        Path webXmlPath = targetDir.resolve("WEB-INF/quickstart-web.xml");
        WebDescriptor descriptor = new WebDescriptor(webapp.getResourceFactory().newResource(webXmlPath));
        descriptor.parse(WebDescriptor.getParser(!QuickStartGeneratorConfiguration.LOG.isDebugEnabled()));
        Node node = descriptor.getRoot();
        assertNotNull(node);

        System.setProperty("jetty.home", targetDir.toString());

        //war file or dir to start
        String war = targetDir.toString();

        //optional jetty context xml file to configure the webapp
        Path testResourceXml = MavenPaths.findTestResourceFile("test.xml");
        Resource contextXml = webapp.getResourceFactory().newResource(testResourceXml);

        Server server = new Server(0);

        webapp.addConfiguration(new QuickStartConfiguration(),
            new EnvConfiguration(),
            new PlusConfiguration(),
            new AnnotationConfiguration());
        webapp.setAttribute(QuickStartConfiguration.MODE, QuickStartConfiguration.Mode.QUICKSTART);
        webapp.setWar(war);
        webapp.setContextPath("/");

        //apply context xml file
        XmlConfiguration xmlConfiguration = new XmlConfiguration(contextXml);
        xmlConfiguration.configure(webapp);

        server.setHandler(webapp);

        server.start();

        URL url = new URL("http://127.0.0.1:" + server.getBean(NetworkConnector.class).getLocalPort() + "/test/dump/info");
        HttpURLConnection connection = (HttpURLConnection)url.openConnection();
        assertEquals(200, connection.getResponseCode());
        assertThat(IO.toString((InputStream)connection.getContent()), Matchers.containsString("Dump Servlet"));

        server.stop();
    }

    @Test
    public void testSpecWar() throws Exception
    {
        WebAppContext webapp = new WebAppContext();

        //Generate the quickstart xml
        PreconfigureSpecWar.main(new String[]{});

        Path workDir = MavenPaths.targetTestDir(PreconfigureSpecWar.class.getSimpleName());
        Path targetDir = workDir.resolve("test-spec-preconfigured");

        Path webXmlPath = targetDir.resolve("WEB-INF/quickstart-web.xml");
        assertTrue(Files.exists(webXmlPath), "Path should exist:" + webXmlPath);

        WebDescriptor descriptor = new WebDescriptor(webapp.getResourceFactory().newResource(webXmlPath));
        descriptor.parse(WebDescriptor.getParser(!QuickStartGeneratorConfiguration.LOG.isDebugEnabled()));
        Node node = descriptor.getRoot();
        assertNotNull(node);

        System.setProperty("jetty.home", targetDir.toString());

        // war file or dir to start
        String war = targetDir.toString();

        //optional jetty context xml file to configure the webapp
        Path testResourceSpec = MavenPaths.findTestResourceFile("test-spec.xml");
        Resource contextXml = webapp.getResourceFactory().newResource(testResourceSpec);

        Server server = new Server(0);

        webapp.addConfiguration(new QuickStartConfiguration(),
            new EnvConfiguration(),
            new PlusConfiguration(),
            new AnnotationConfiguration());
        webapp.setAttribute(QuickStartConfiguration.MODE, QuickStartConfiguration.Mode.QUICKSTART);
        webapp.setWar(war);
        webapp.setContextPath("/");

        //apply context xml file
        // System.err.println("Applying "+contextXml);
        XmlConfiguration xmlConfiguration = new XmlConfiguration(contextXml);
        xmlConfiguration.configure(webapp);

        server.setHandler(webapp);
        server.start();

        //test static content added by fragment
        URL url = new URL("http://127.0.0.1:" + server.getBean(NetworkConnector.class).getLocalPort() + "/fragmentA/index.html");
        HttpURLConnection connection = (HttpURLConnection)url.openConnection();
        assertEquals(200, connection.getResponseCode());
        String content = IO.toString((InputStream)connection.getContent());
        assertThat(content, Matchers.containsString("Welcome to a Fragment"));

        //test annotations etc
        url = new URL("http://127.0.0.1:" + server.getBean(NetworkConnector.class).getLocalPort() + "/test/");
        connection = (HttpURLConnection)url.openConnection();
        connection.setRequestMethod("POST");

        assertEquals(200, connection.getResponseCode());
        content = IO.toString((InputStream)connection.getContent());
        assertThat(content, Matchers.containsString("Results"));
        assertThat(content, Matchers.not(Matchers.containsString("FAIL")));
        server.stop();
    }

    @Test
    public void testJNDIWar() throws Exception
    {
        WebAppContext webapp = new WebAppContext();

        //Generate the quickstart
        PreconfigureJNDIWar.main(new String[]{});

        Path workDir = MavenPaths.targetTestDir(PreconfigureJNDIWar.class.getSimpleName());
        Path targetDir = workDir.resolve("test-jndi-preconfigured");

        Path webXmlPath = targetDir.resolve("WEB-INF/quickstart-web.xml");
        assertTrue(Files.exists(webXmlPath), "Exists: " + webXmlPath);
        WebDescriptor descriptor = new WebDescriptor(webapp.getResourceFactory().newResource(webXmlPath));
        descriptor.parse(WebDescriptor.getParser(!QuickStartGeneratorConfiguration.LOG.isDebugEnabled()));
        Node node = descriptor.getRoot();
        assertNotNull(node);

        System.setProperty("jetty.home", targetDir.toString());

        //war file or dir to start
        String war = targetDir.toString();

        //optional jetty context xml file to configure the webapp
        Path testResourceJndi = MavenPaths.findTestResourceFile("test-jndi.xml");
        Resource contextXml = webapp.getResourceFactory().newResource(testResourceJndi);

        Server server = new Server(0);

        webapp.addConfiguration(new QuickStartConfiguration(),
            new EnvConfiguration(),
            new PlusConfiguration(),
            new AnnotationConfiguration());
        webapp.setAttribute(QuickStartConfiguration.MODE, QuickStartConfiguration.Mode.QUICKSTART);
        webapp.setWar(war);
        webapp.setContextPath("/");

        //apply context xml file
        // System.err.println("Applying "+contextXml);
        XmlConfiguration xmlConfiguration = new XmlConfiguration(contextXml);
        xmlConfiguration.configure(webapp);

        server.setHandler(webapp);

        server.start();

        URL url = new URL("http://127.0.0.1:" + server.getBean(NetworkConnector.class).getLocalPort() + "/");
        HttpURLConnection connection = (HttpURLConnection)url.openConnection();
        String content = IO.toString((InputStream)connection.getContent());
        assertEquals(200, connection.getResponseCode());
        assertThat(content, Matchers.containsString("JNDI Demo WebApp"));

        server.stop();
    }

    @Test
    public void testFilterMappings() throws Exception
    {
        Path workdir = MavenPaths.targetTestDir(PreconfigureSpecWar.class.getSimpleName());
        FS.ensureEmpty(workdir);
        Path target = workdir.resolve("test-filter-mappings");
        FS.ensureEmpty(target);
        FS.ensureDirExists(target.resolve("WEB-INF"));

        Path sourceWebXml = MavenPaths.findTestResourceFile("filter-web.xml");
        Files.copy(sourceWebXml, target.resolve("WEB-INF/web.xml"));
        System.setProperty("jetty.home", target.toString());

        PreconfigureQuickStartWar.main(target.toString());

        Path quickStartXml = target.resolve("WEB-INF/quickstart-web.xml");
        String quickStartContents = Files.readString(quickStartXml);
        assertThat(quickStartContents, containsString("""
              <filter>
                <filter-name>CustomFilter</filter-name>
                <filter-class>org.example.CustomFilter</filter-class>
                <async-supported>false</async-supported>
              </filter>
              <filter-mapping>
                <filter-name>CustomFilter</filter-name>
                <url-pattern>/foo/*</url-pattern>
                <dispatcher>REQUEST</dispatcher>
                <dispatcher>ERROR</dispatcher>
                <dispatcher>FORWARD</dispatcher>
                <dispatcher>INCLUDE</dispatcher>
              </filter-mapping>
            """));
    }

    @Test
    public void testSameSiteCookie() throws Exception
    {
        Path workdir = MavenPaths.targetTestDir(PreconfigureSpecWar.class.getSimpleName());
        FS.ensureEmpty(workdir);
        Path target = workdir.resolve("test-cookie_samesite");
        FS.ensureEmpty(target);
        FS.ensureDirExists(target.resolve("WEB-INF"));

        Path sourceWebXml = MavenPaths.findTestResourceFile("cookie-web.xml");
        Files.copy(sourceWebXml, target.resolve("WEB-INF/web.xml"));
        System.setProperty("jetty.home", target.toString());

        PreconfigureQuickStartWar.main(target.toString());

        Path quickStartXml = target.resolve("WEB-INF/quickstart-web.xml");
        String quickStartContents = Files.readString(quickStartXml);
        assertThat(quickStartContents, containsString("""
                <cookie-config>
                  <comment>foo__SAME_SITE_NONE__</comment>
            """));
    }
}
