//
// ========================================================================
// 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.tests.distribution;

import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;
import java.util.stream.Stream;

import org.eclipse.jetty.client.ContentResponse;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.tests.testers.JettyHomeTester;
import org.eclipse.jetty.tests.testers.Tester;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;

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

@Disabled //TODO
public class LoggingOptionsTests extends AbstractJettyHomeTest
{
    public static Stream<Arguments> validLoggingModules()
    {
        List<Arguments> arguments = new ArrayList<>();
        
        for (String env : new String[] {"ee9", "ee10"})
        {
            arguments.add(Arguments.of(env, "logging-jetty",
                Arrays.asList(
                    "\\$\\{jetty.home\\}[/\\\\]lib[/\\\\]logging[/\\\\]slf4j-api-.*\\.jar",
                    "\\$\\{jetty.home\\}[/\\\\]lib[/\\\\]logging[/\\\\]jetty-slf4j-impl-.*\\.jar"),
                Arrays.asList(
                    "logging/slf4j",
                    "logging-jetty"
                )
            ));
            arguments.add(Arguments.of(env, "logging-logback",
                Arrays.asList(
                    "\\$\\{jetty.home\\}[/\\\\]lib[/\\\\]logging[/\\\\]slf4j-api-.*\\.jar",
                    "\\$\\{jetty.base\\}[/\\\\]lib[/\\\\]logging[/\\\\]logback-classic-.*\\.jar",
                    "\\$\\{jetty.base\\}[/\\\\]lib[/\\\\]logging[/\\\\]logback-core-.*\\.jar"
                ),
                Arrays.asList(
                    "logging/slf4j",
                    "logging-logback"
                )
            ));
            arguments.add(Arguments.of(env, "logging-jul",
                Arrays.asList(
                    "\\$\\{jetty.home\\}[/\\\\]lib[/\\\\]logging[/\\\\]slf4j-api-.*\\.jar",
                    "\\$\\{jetty.base\\}[/\\\\]lib[/\\\\]logging[/\\\\]slf4j-jdk14-.*\\.jar"
                ),
                Arrays.asList(
                    "logging/slf4j",
                    "logging-jul"
                )
            ));
            arguments.add(Arguments.of(env, "logging-log4j1",
                Arrays.asList(
                    "\\$\\{jetty.home\\}[/\\\\]lib[/\\\\]logging[/\\\\]slf4j-api-.*\\.jar",
                    "\\$\\{jetty.base\\}[/\\\\]lib[/\\\\]logging[/\\\\]slf4j-reload4j-.*\\.jar"
                ),
                Arrays.asList(
                    "logging/slf4j",
                    "logging-log4j1"
                )
            ));
            arguments.add(Arguments.of(env, "logging-log4j2",
                Arrays.asList(
                    "\\$\\{jetty.home\\}[/\\\\]lib[/\\\\]logging[/\\\\]slf4j-api-.*\\.jar",
                    "\\$\\{jetty.base\\}[/\\\\]lib[/\\\\]logging[/\\\\]log4j-slf4j2-impl-.*\\.jar",
                    "\\$\\{jetty.base\\}[/\\\\]lib[/\\\\]logging[/\\\\]log4j-api-.*\\.jar",
                    "\\$\\{jetty.base\\}[/\\\\]lib[/\\\\]logging[/\\\\]log4j-core-.*\\.jar"
                ),
                Arrays.asList(
                    "logging/slf4j",
                    "logging-log4j2"
                )
            ));
            // Disabled, as slf4j noop is not supported by output/log monitoring of AbstractJettyHomeTest
            /* Arguments.of("logging-noop",
                Arrays.asList(
                    "\\$\\{jetty.home\\}[/\\\\]lib[/\\\\]logging[/\\\\]slf4j-api-.*\\.jar"
                ), Arrays.asList(
                    "logging/slf4j",
                    "logging-log4j2"
                )
            ),*/
            arguments.add(Arguments.of(env, "logging-logback,logging-jcl-capture,logging-jul-capture,logging-log4j1-capture",
                Arrays.asList(
                    "\\$\\{jetty.home\\}[/\\\\]lib[/\\\\]logging[/\\\\]slf4j-api-.*\\.jar",
                    "\\$\\{jetty.base\\}[/\\\\]lib[/\\\\]logging[/\\\\]logback-classic-.*\\.jar",
                    "\\$\\{jetty.base\\}[/\\\\]lib[/\\\\]logging[/\\\\]logback-core-.*\\.jar",
                    "\\$\\{jetty.base\\}[/\\\\]lib[/\\\\]logging[/\\\\]jcl-over-slf4j-.*\\.jar",
                    "\\$\\{jetty.base\\}[/\\\\]lib[/\\\\]logging[/\\\\]jul-to-slf4j-.*\\.jar",
                    "\\$\\{jetty.base\\}[/\\\\]lib[/\\\\]logging[/\\\\]log4j-over-slf4j-.*\\.jar"
                ),
                Arrays.asList(
                    "logging/slf4j",
                    "logging-logback",
                    "logging-jcl-capture",
                    "logging-jul-capture",
                    "logging-log4j1-capture"
                )
            ));
        }
        
        return arguments.stream();
    }

    @ParameterizedTest(name = "[{index}] {0}")
    @MethodSource("validLoggingModules")
    public void testLoggingConfiguration(String env, String loggingModules, List<String> expectedClasspathEntries,
                                         List<String> expectedEnabledModules) throws Exception
    {
        Path jettyBase = newTestJettyBaseDirectory();
        String jettyVersion = System.getProperty("jettyVersion");
        JettyHomeTester distribution = JettyHomeTester.Builder.newInstance()
            .jettyVersion(jettyVersion)
            .jettyBase(jettyBase)
            .build();

        String[] args1 = {
            "--approve-all-licenses",
            "--add-modules=resources,server,http, " + toEnvironment("webapp", env) + "," + toEnvironment("deploy", env) + "," + toEnvironment("jsp", env),
            "--add-modules=" + loggingModules
        };
        try (JettyHomeTester.Run installRun = distribution.start(args1))
        {
            assertTrue(installRun.awaitFor(START_TIMEOUT, TimeUnit.SECONDS));
            assertEquals(0, installRun.getExitValue());

            try (JettyHomeTester.Run listConfigRun = distribution.start("--list-config"))
            {
                assertTrue(listConfigRun.awaitFor(START_TIMEOUT, TimeUnit.SECONDS));
                assertEquals(0, listConfigRun.getExitValue());

                List<String> rawConfigLogs = new ArrayList<>(listConfigRun.getLogs());

                for (String expectedEnabledModule : expectedEnabledModules)
                {
                    containsEntryWith("Expected Enabled Module", rawConfigLogs, expectedEnabledModule);
                }

                for (String expectedClasspathEntry : expectedClasspathEntries)
                {
                    containsEntryWith("Expected Classpath Entry", rawConfigLogs, expectedClasspathEntry);
                }
            }

            Path war = distribution.resolveArtifact("org.eclipse.jetty." + env + ".demos:jetty-" + env + ".demo-jsp-webapp:war:" + jettyVersion);
            distribution.installWar(war, "test");

            int port = Tester.freePort();
            try (JettyHomeTester.Run requestRun = distribution.start("jetty.http.port=" + port))
            {
                assertTrue(requestRun.awaitConsoleLogsFor("Started oejs.Server@", START_TIMEOUT, TimeUnit.SECONDS));

                startHttpClient();
                ContentResponse response = client.GET("http://localhost:" + port + "/test/index.jsp");
                assertEquals(HttpStatus.OK_200, response.getStatus());
                assertThat(response.getContentAsString(), containsString("JSP Examples"));
                assertThat(response.getContentAsString(), not(containsString("<%")));
            }
        }
    }

    private void containsEntryWith(String reason, List<String> logs, String expectedEntry)
    {
        Pattern pat = Pattern.compile(expectedEntry);
        assertThat("Count of matches for [" + expectedEntry + "]", logs.stream().filter(pat.asPredicate()).count(), greaterThanOrEqualTo(1L));
    }
}
