package org.jboss.installer.screens.jsf;

import org.jboss.installer.core.MnemonicUtils;
import org.jboss.installer.core.ValidationResult;
import org.jboss.installer.postinstall.task.JsfLibraryTask;
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 java.io.File;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;

import static org.assertj.core.api.Assertions.assertThat;
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.screens.JSFInstallScreen.JSF_VERSION_KEY;
import static org.jboss.installer.screens.jsf.CreateNewChannelPanel.CHANNEL_REPOSITORY_LABEL_KEY;
import static org.jboss.installer.screens.jsf.CreateNewChannelPanel.MYFACES_REPOSITORY_LABEL_KEY;
import static org.jboss.installer.validators.CertificateSecurityDomainValidator.GENERIC_VALIDATION_EMPTY_FIELD;
import static org.jboss.installer.validators.JsfValidator.JSF_VERSION_NOT_SUPPORTED_KEY;
import static org.jboss.installer.validators.MavenRepositoryValidator.LOCAL_REPO_PATH_ERROR_KEY;
import static org.jboss.installer.validators.MavenRepositoryValidator.REMOTE_REPO_PATH_ERROR_KEY;
import static org.jboss.installer.validators.RepositoryContentValidator.ARTIFACT_NOT_FOUND;
import static org.junit.Assert.assertEquals;

public class CreateNewChannelPanelTest {

    private static final String JSF_VERSION = "4.0.1";

    @Rule
    public TemporaryFolder temp = new TemporaryFolder();

    private MockLanguageUtils langUtils = new MockLanguageUtils();
    private Path targetChannelRepo;

    @Before
    public void setUp() throws Exception {
        targetChannelRepo = temp.newFolder("target-jsf-repo").toPath();
    }

    @Test
    public void validValues() throws Exception {
        final TestableCreateNewChannelPanel panel = new TestableCreateNewChannelPanel(MavenUtils.CENTRAL_REPOSITORY_URL,
                targetChannelRepo.toString(), JSF_VERSION);

        final ValidationResult result = panel.validateInput();
        assertThat(result)
                .isIn(ValidationResult.ok(), ValidationResult.warning(langUtils.getString("jsf_install.path_too_long_warn")));

        final JsfLibraryTask.Config config = new JsfLibraryTask.Config();
        panel.populateConfig(config);

        assertEquals(JSF_VERSION, config.getJsfVersion());
        assertThat(config.getRemoteMavenRepositoryUrls())
                .containsExactly(new URL(MavenUtils.CENTRAL_REPOSITORY_URL));
        assertEquals(targetChannelRepo.toString(), config.getLocalChannelRepositoryPath());
        assertEquals(JsfLibraryTask.Config.JsfProject.MyFaces, config.getJsfProject());
    }

    @Test
    public void validValuesWithLocalPath() throws Exception {
        final File tempRepo = temp.newFolder("test-repo");
        MavenUtils.deployMyFacesArtifactsLocally(JSF_VERSION, MavenUtils.CENTRAL_REPOSITORY_URL, tempRepo.toURI().toURL().toExternalForm());

        final TestableCreateNewChannelPanel panel = new TestableCreateNewChannelPanel(tempRepo.toPath().toString(),
                targetChannelRepo.toString(), JSF_VERSION);

        final ValidationResult result = panel.validateInput();
        assertThat(result)
                .isIn(ValidationResult.ok(), ValidationResult.warning(langUtils.getString("jsf_install.path_too_long_warn")));

        final JsfLibraryTask.Config config = new JsfLibraryTask.Config();
        panel.populateConfig(config);

        assertEquals(JSF_VERSION, config.getJsfVersion());
        assertThat(config.getRemoteMavenRepositoryUrls())
                .containsExactly(tempRepo.toURI().toURL());
        assertEquals(targetChannelRepo.toString(), config.getLocalChannelRepositoryPath());
        assertEquals(JsfLibraryTask.Config.JsfProject.MyFaces, config.getJsfProject());
    }

    @Test
    public void nullJsfVersionReturnsError() throws Exception {
        final TestableCreateNewChannelPanel panel = new TestableCreateNewChannelPanel("https://foo.bar",
                targetChannelRepo.toString(), null);

        final ValidationResult result = panel.validateInput();
        assertEquals(result.getMessage(), ValidationResult.Result.ERROR, result.getResult());
        assertThat(result.getMessage())
                .startsWith(GENERIC_VALIDATION_EMPTY_FIELD)
                .contains(JSF_VERSION_KEY);
    }

    @Test
    public void whitespaceJsfVersionReturnsError() throws Exception {
        final TestableCreateNewChannelPanel panel = new TestableCreateNewChannelPanel("https://foo.bar",
                targetChannelRepo.toString(), "   ");

        final ValidationResult result = panel.validateInput();
        assertEquals(result.getMessage(), ValidationResult.Result.ERROR, result.getResult());
        assertThat(result.getMessage())
                .startsWith(GENERIC_VALIDATION_EMPTY_FIELD)
                .contains(JSF_VERSION_KEY);
    }

    @Test
    public void emptyJsfVersionReturnsError() throws Exception {
        final TestableCreateNewChannelPanel panel = new TestableCreateNewChannelPanel("https://foo.bar",
                targetChannelRepo.toString(),"");

        final ValidationResult result = panel.validateInput();
        assertEquals(result.getMessage(), ValidationResult.Result.ERROR, result.getResult());
        assertThat(result.getMessage())
                .startsWith(GENERIC_VALIDATION_EMPTY_FIELD)
                .contains(JSF_VERSION_KEY);
    }

    @Test
    public void nullChannelPathReturnsError() throws Exception {
        final TestableCreateNewChannelPanel panel = new TestableCreateNewChannelPanel("https://foo.bar", null, JSF_VERSION);

        final ValidationResult result = panel.validateInput();
        assertEquals(result.getMessage(), ValidationResult.Result.ERROR, result.getResult());
        assertThat(result.getMessage())
                .startsWith(GENERIC_VALIDATION_EMPTY_FIELD)
                .contains(CHANNEL_REPOSITORY_LABEL_KEY);
    }

    @Test
    public void whitespaceChannelRepositoryReturnsError() throws Exception {
        final TestableCreateNewChannelPanel panel = new TestableCreateNewChannelPanel("https://foo.bar", "    ", JSF_VERSION);

        final ValidationResult result = panel.validateInput();
        assertEquals(result.getMessage(), ValidationResult.Result.ERROR, result.getResult());
        assertThat(result.getMessage())
                .startsWith(GENERIC_VALIDATION_EMPTY_FIELD)
                .contains(CHANNEL_REPOSITORY_LABEL_KEY);
    }

    @Test
    public void emptyChannelRepositoryReturnsError() throws Exception {
        final TestableCreateNewChannelPanel panel = new TestableCreateNewChannelPanel("https://foo.bar", "", JSF_VERSION);

        final ValidationResult result = panel.validateInput();
        assertEquals(result.getMessage(), ValidationResult.Result.ERROR, result.getResult());
        assertThat(result.getMessage())
                .startsWith(GENERIC_VALIDATION_EMPTY_FIELD)
                .contains(CHANNEL_REPOSITORY_LABEL_KEY);
    }

    @Test
    public void whitespaceSourceRepositoryReturnsError() throws Exception {
        final TestableCreateNewChannelPanel panel = new TestableCreateNewChannelPanel("    ",
                targetChannelRepo.toString(), JSF_VERSION);

        final ValidationResult result = panel.validateInput();
        assertEquals(result.getMessage(), ValidationResult.Result.ERROR, result.getResult());
        assertThat(result.getMessage())
                .startsWith(GENERIC_VALIDATION_EMPTY_FIELD)
                .contains(MYFACES_REPOSITORY_LABEL_KEY);
    }

    @Test
    public void emptySourceRepositoryReturnsError() throws Exception {
        final TestableCreateNewChannelPanel panel = new TestableCreateNewChannelPanel("",
                targetChannelRepo.toString(), JSF_VERSION);

        final ValidationResult result = panel.validateInput();
        assertEquals(result.getMessage(), ValidationResult.Result.ERROR, result.getResult());
        assertThat(result.getMessage())
                .startsWith(GENERIC_VALIDATION_EMPTY_FIELD)
                .contains(MYFACES_REPOSITORY_LABEL_KEY);
    }

    @Test
    public void nullSourceRepositoryReturnsError() throws Exception {
        final TestableCreateNewChannelPanel panel = new TestableCreateNewChannelPanel(null,
                targetChannelRepo.toString(), JSF_VERSION);

        final ValidationResult result = panel.validateInput();
        assertEquals(result.getMessage(), ValidationResult.Result.ERROR, result.getResult());
        assertThat(result.getMessage())
                .startsWith(GENERIC_VALIDATION_EMPTY_FIELD)
                .contains(MYFACES_REPOSITORY_LABEL_KEY);
    }

    @Test
    public void invalidUrlStringReturnsError() throws Exception {
        final TestableCreateNewChannelPanel panel = new TestableCreateNewChannelPanel("http://invalid",
                targetChannelRepo.toString(), JSF_VERSION);

        final ValidationResult result = panel.validateInput();
        assertEquals(result.getMessage(), ValidationResult.Result.ERROR, result.getResult());
        assertThat(result.getMessage())
                .isEqualTo(REMOTE_REPO_PATH_ERROR_KEY);
    }

    @Test
    public void nonExistingRepositoryPathReturnsError() throws Exception {
        final TestableCreateNewChannelPanel panel = new TestableCreateNewChannelPanel(Path.of("i", "dont", "exist").toString(),
                targetChannelRepo.toString(), JSF_VERSION);

        final ValidationResult result = panel.validateInput();
        assertEquals(result.getMessage(), ValidationResult.Result.ERROR, result.getResult());
        assertThat(result.getMessage())
                .isEqualTo(LOCAL_REPO_PATH_ERROR_KEY);
    }

    @Test
    public void nonEmptyRepositoryPathReturnsError() throws Exception {
        final File tempRepo = temp.newFolder("test-repo");
        Files.writeString(tempRepo.toPath().resolve("test.txt"), "test");
        final TestableCreateNewChannelPanel panel = new TestableCreateNewChannelPanel(MavenUtils.CENTRAL_REPOSITORY_URL,
                tempRepo.toString(), JSF_VERSION);

        final ValidationResult result = panel.validateInput();
        assertEquals(result.getMessage(), ValidationResult.Result.ERROR, result.getResult());
        assertThat(result.getMessage())
                .startsWith("jsf_install.nonempty");
    }


    @Test
    public void fileChannelRepoPathReturnsError() throws Exception {
        final File fileAsRepo = temp.newFile("test-file");
        Files.writeString(fileAsRepo.toPath(), "foo");
        final TestableCreateNewChannelPanel panel = new TestableCreateNewChannelPanel(MavenUtils.CENTRAL_REPOSITORY_URL,
                fileAsRepo.toString(), JSF_VERSION);

        final ValidationResult result = panel.validateInput();
        assertEquals(result.getMessage(), ValidationResult.Result.ERROR, result.getResult());
        assertThat(result.getMessage())
                .startsWith("jsf_install.isfile");
    }

    @Test
    public void urlChannelRepoPathReturnsError() throws Exception {
        final File fileAsRepo = temp.newFile("test-file");
        Files.writeString(fileAsRepo.toPath(), "foo");
        final TestableCreateNewChannelPanel panel = new TestableCreateNewChannelPanel(MavenUtils.CENTRAL_REPOSITORY_URL,
                fileAsRepo.toURI().toURL().toExternalForm(), JSF_VERSION);

        final ValidationResult result = panel.validateInput();
        assertEquals(result.getMessage(), ValidationResult.Result.ERROR, result.getResult());
        assertThat(result.getMessage())
                .startsWith("jsf_install.invalid_char");
    }

    @Test
    public void nonExistingArtifactsReturnsError() throws Exception {
        final TestableCreateNewChannelPanel panel = new TestableCreateNewChannelPanel(MavenUtils.CENTRAL_REPOSITORY_URL,
                targetChannelRepo.toString(), "4.0.1-idontexist");

        final ValidationResult result = panel.validateInput();
        assertEquals(result.getMessage(), ValidationResult.Result.ERROR, result.getResult());
        assertThat(result.getMessage())
                .isEqualTo(langUtils.getString(ARTIFACT_NOT_FOUND, MYFACES_GROUP_ID, MYFACES_API_ARTIFACT_ID, "4.0.1-idontexist",
                        MavenUtils.CENTRAL_REPOSITORY_URL));
    }

    @Test
    public void jsfVersionOtherThan4ReturnsError() throws Exception {
        final TestableCreateNewChannelPanel panel = new TestableCreateNewChannelPanel(MavenUtils.CENTRAL_REPOSITORY_URL,
                targetChannelRepo.toString(), "5.0.1");

        final ValidationResult result = panel.validateInput();
        assertEquals(result.getMessage(), ValidationResult.Result.ERROR, result.getResult());
        assertThat(result.getMessage())
                .isEqualTo(langUtils.getString(JSF_VERSION_NOT_SUPPORTED_KEY, "5.0.1"));
    }





    private class TestableCreateNewChannelPanel extends CreateNewChannelPanel {

        private final String targetChannelPath;
        private String sourceRepositoryValue;
        private String jsfVersion;
        public TestableCreateNewChannelPanel(String sourceRepositoryValue, String targetChannelPath, String jsfVersion) {
            super(langUtils, new MnemonicUtils(), Path.of("."));
            this.sourceRepositoryValue = sourceRepositoryValue;
            this.targetChannelPath = targetChannelPath;
            this.jsfVersion = jsfVersion;
        }

        @Override
        protected String getSourceRepositoryValue() {
            return sourceRepositoryValue;
        }

        @Override
        protected String getJsfVersion() {
            return jsfVersion;
        }

        @Override
        protected String getTargetChannelPath() {
            return targetChannelPath;
        }
    }

}