package org.jboss.installer.validators;

import org.eclipse.aether.artifact.DefaultArtifact;
import org.jboss.installer.core.LanguageUtils;
import org.jboss.installer.core.ValidationResult;
import org.jboss.installer.postinstall.task.jsf.MyFacesJsfLibrarySetup;
import org.jboss.installer.test.utils.MavenUtils;
import org.jboss.installer.test.utils.MockLanguageUtils;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.wildfly.channel.ChannelManifest;
import org.wildfly.channel.ChannelManifestMapper;

import java.io.File;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;
import static org.jboss.installer.postinstall.task.jsf.MyFacesJsfLibrarySetup.DEFAULT_CHANNEL_ARTIFACT_ID;
import static org.jboss.installer.postinstall.task.jsf.MyFacesJsfLibrarySetup.DEFAULT_CHANNEL_GROUP_ID;
import static org.jboss.installer.postinstall.task.jsf.MyFacesJsfLibrarySetup.MYFACES_API_ARTIFACT_ID;
import static org.jboss.installer.postinstall.task.jsf.MyFacesJsfLibrarySetup.MYFACES_GROUP_ID;
import static org.jboss.installer.validators.RepositoryContentValidator.ARTIFACT_NOT_FOUND;
import static org.jboss.installer.validators.RepositoryContentValidator.INVALID_MANIFEST;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

public class RepositoryContentValidatorTest {

    private static final String JSF_VERSION = "4.0.1";
    private final LanguageUtils langUtils = new MockLanguageUtils();
    private RepositoryContentValidator validator;

    @Rule
    public TemporaryFolder temp = new TemporaryFolder();

    @Before
    public void setUp() throws Exception {
        validator = new RepositoryContentValidator(langUtils);
    }

    @Test
    public void existingJar() throws Exception {
        final ValidationResult result = validator
                .validate(new URL(MavenUtils.CENTRAL_REPOSITORY_URL), "org.aesh", "aesh", "2.7");


        assertEquals(ValidationResult.ok(), result);
    }

    @Test
    public void nonExistingJar() throws Exception {
        final ValidationResult result = validator
                .validate(new URL(MavenUtils.CENTRAL_REPOSITORY_URL), "idont", "exist", "4.9");


        assertEquals(ValidationResult.error(langUtils.getString(ARTIFACT_NOT_FOUND, "idont", "exist", "4.9",
                MavenUtils.CENTRAL_REPOSITORY_URL)), result);
    }

    @Test
    public void existingJarRepoNoTrailingSlash() throws Exception {
        // sanity check value
        assertTrue("The central repository URL value should end with trailing slash", MavenUtils.CENTRAL_REPOSITORY_URL.endsWith("/"));
        final ValidationResult result = validator
                .validate(new URL(MavenUtils.CENTRAL_REPOSITORY_URL.replaceAll("/$", "")),
                        "org.aesh", "aesh", "2.7");


        assertEquals(ValidationResult.ok(), result);
    }

    @Test
    public void channelIsValid() throws Exception {
        final File channelRepository = temp.newFolder();
        final URL channelRepositoryURL = channelRepository.toURI().toURL();
        final String channelManifest = new MyFacesJsfLibrarySetup(temp.newFolder().toPath(), langUtils).createChannelManifest(JSF_VERSION, channelRepository.toPath().toString());
        MavenUtils.deployMyFacesArtifactsLocally(JSF_VERSION, MavenUtils.CENTRAL_REPOSITORY_URL, channelRepositoryURL.toExternalForm());

        assertEquals(ValidationResult.ok() ,validator.validateManifest(channelRepositoryURL, channelManifest.split(":")[0], channelManifest.split(":")[1]));
    }

    @Test
    public void artifactsNotAvailableIsError() throws Exception {
        final File channelRepository = temp.newFolder();
        final URL channelRepositoryURL = channelRepository.toURI().toURL();
        final String channelManifest = new MyFacesJsfLibrarySetup(temp.newFolder().toPath(), langUtils).createChannelManifest(JSF_VERSION, channelRepository.toPath().toString());

        assertEquals(ValidationResult.error(langUtils.getString(ARTIFACT_NOT_FOUND, MYFACES_GROUP_ID,
                        MYFACES_API_ARTIFACT_ID, JSF_VERSION, channelRepositoryURL.toExternalForm())) ,
                validator.validateManifest(channelRepositoryURL, channelManifest.split(":")[0], channelManifest.split(":")[1]));
    }

    @Test
    public void manifestDoesntHaveMyFacesStreamsAvailableIsError() throws Exception {
        final File channelRepository = temp.newFolder();
        final URL channelRepositoryURL = channelRepository.toURI().toURL();
        final ChannelManifest channelManifest = new ChannelManifest("MyFaces manifest", "myfaces", null, List.of());
        final File manifestFile = temp.newFile("manifest.yaml");
        Files.writeString(manifestFile.toPath(), ChannelManifestMapper.toYaml(channelManifest), StandardCharsets.UTF_8);
        MyFacesJsfLibrarySetup.deployToRepository(channelRepository.toPath(), new DefaultArtifact(DEFAULT_CHANNEL_GROUP_ID, DEFAULT_CHANNEL_ARTIFACT_ID,
                "manifest", "yaml", "1.0.0", null, manifestFile));

        assertEquals(ValidationResult.error(langUtils.getString(ARTIFACT_NOT_FOUND, MYFACES_GROUP_ID,
                        MYFACES_API_ARTIFACT_ID, "", channelRepositoryURL.toExternalForm())),
                validator.validateManifest(channelRepositoryURL, DEFAULT_CHANNEL_GROUP_ID, DEFAULT_CHANNEL_ARTIFACT_ID));
    }

    @Test
    public void invalidManifestIsError() throws Exception {
        final File channelRepository = temp.newFolder();
        final URL channelRepositoryURL = channelRepository.toURI().toURL();
        final ChannelManifest channelManifest = new ChannelManifest("MyFaces manifest", "myfaces", null, List.of());
        final File manifestFile = temp.newFile("manifest.yaml");
        final String validYaml = ChannelManifestMapper.toYaml(channelManifest);
        String invalidYaml = validYaml.replaceAll(".*schemaVersion:.*", "");
        Files.writeString(manifestFile.toPath(), invalidYaml, StandardCharsets.UTF_8);
        MyFacesJsfLibrarySetup.deployToRepository(channelRepository.toPath(), new DefaultArtifact(DEFAULT_CHANNEL_GROUP_ID, DEFAULT_CHANNEL_ARTIFACT_ID,
                "manifest", "yaml", "1.0.0", null, manifestFile));

        final ValidationResult validationResult = validator.validateManifest(channelRepositoryURL, DEFAULT_CHANNEL_GROUP_ID, DEFAULT_CHANNEL_ARTIFACT_ID);
        assertEquals(ValidationResult.Result.ERROR, validationResult.getResult());
        assertThat(validationResult.getMessage())
                        .startsWith(INVALID_MANIFEST);
    }
}