/*
 * Copyright 2022 Red Hat, Inc. and/or its affiliates
 * and other contributors as indicated by the @author tags.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.jboss.installer.validators;

import org.jboss.installer.core.ValidationResult;
import org.jboss.installer.test.utils.MockLanguageUtils;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import static org.assertj.core.api.Assertions.assertThat;
import static org.jboss.installer.screens.QuickstartsMavenRepositorySetupScreen.DEFAULT_MAVEN_REPOSITORY;
import static org.jboss.installer.validators.FileValidator.NOT_EXISTS_ERROR;
import static org.jboss.installer.validators.MavenOfflineRepositoryValidator.EMPTY_ERROR;
import static org.jboss.installer.validators.MavenOfflineRepositoryValidator.MALFORMED_URL_ERROR;
import static org.jboss.installer.validators.MavenOfflineRepositoryValidator.MULTIPLE_REPO_ROOTS;
import static org.jboss.installer.validators.MavenOfflineRepositoryValidator.NEITHER_DIRECTORY_NOR_ZIPFILE_ERROR;
import static org.jboss.installer.validators.MavenOfflineRepositoryValidator.NO_REPO_ROOTS;

public class MavenOfflineRepositoryValidatorTest {

    @Rule
    public TemporaryFolder temp = new TemporaryFolder();

    private final MavenOfflineRepositoryValidator validator = new MavenOfflineRepositoryValidator(new MockLanguageUtils());

    @Test
    public void validateFile() throws Exception {
        final Path tempFilePath = temp.newFile("temp.zip").toPath();
        Assert.assertTrue(validator.validate(tempFilePath.toString()).getMessage().contains(NEITHER_DIRECTORY_NOR_ZIPFILE_ERROR));
        Files.delete(tempFilePath);
        Assert.assertTrue(validator.validate(tempFilePath.toString()).getMessage().contains(NOT_EXISTS_ERROR));
    }

    @Test
    public void validateFileURL() throws Exception {
        final Path tempFilePath = temp.newFile("temp.zip").toPath();
        Assert.assertTrue(validator.validate(tempFilePath.toAbsolutePath().toUri().toURL().toString()).getMessage().contains(NEITHER_DIRECTORY_NOR_ZIPFILE_ERROR));
        Files.delete(tempFilePath);
        Assert.assertTrue(validator.validate(tempFilePath.toAbsolutePath().toUri().toURL().toString()).getMessage().contains(NOT_EXISTS_ERROR));
    }

    @Test
    public void validateDirectory() throws Exception {
        final Path tempFilePath = temp.newFolder("test-offline-repo").toPath();
        Assert.assertEquals(ValidationResult.Result.OK, validator.validate(tempFilePath.toString()).getResult());
    }

    @Test
    public void validateNotValidZipFile() throws Exception {
        final Path tempFilePath = temp.newFile("temp.zip").toPath();
        Files.write(tempFilePath, "not zip file".getBytes(StandardCharsets.UTF_8));
        Assert.assertTrue(validator.validate(tempFilePath.toString()).getMessage().contains(NEITHER_DIRECTORY_NOR_ZIPFILE_ERROR));
    }

    @Test
    public void validateListURLs() {
        final String repositories = DEFAULT_MAVEN_REPOSITORY + "," + DEFAULT_MAVEN_REPOSITORY;
        Assert.assertEquals(ValidationResult.Result.OK, validator.validate(repositories.toString()).getResult());
    }

    @Test
    public void validateMalformedURL() {
        final String repositories = DEFAULT_MAVEN_REPOSITORY + ",https://&$%^#/repo1.maven.org/maven2/";
        final ValidationResult result = validator.validate(repositories.toString());
        Assert.assertEquals(ValidationResult.Result.ERROR, result.getResult());
        Assert.assertTrue(result.getMessage().contains(MALFORMED_URL_ERROR));
    }

    @Test
    public void validateSpaceSuffixURL() {
        final String repositories = DEFAULT_MAVEN_REPOSITORY + " , https://repo1.maven.org/maven2/ ";
        final ValidationResult result = validator.validate(repositories.toString());
        Assert.assertEquals(ValidationResult.Result.OK, result.getResult());
    }

    @Test
    public void validateEmptyInput() {
        final String input = "";
        Assert.assertTrue(validator.validate(input).getMessage().contains(EMPTY_ERROR));
    }

    @Test
    public void validateZip() throws Exception {
        Path zip = createTempZipFile(1);
        Assert.assertEquals(ValidationResult.Result.OK, validator.validate(zip.toUri().toString()).getResult());
    }

    @Test
    public void validateZipWithoutRepoRoots() throws Exception {
        Path zip = createTempZipFile(0);
        final ValidationResult result = validator.validate(zip.toUri().toString());
        Assert.assertEquals(ValidationResult.Result.ERROR, result.getResult());
        Assert.assertTrue(result.getMessage().contains(NO_REPO_ROOTS));
    }

    @Test
    public void validateZipTwoRepoRoots() throws Exception {
        Path zip = createTempZipFile(2);
        final ValidationResult result = validator.validate(zip.toUri().toString());
        Assert.assertEquals(ValidationResult.Result.ERROR, result.getResult());
        Assert.assertTrue(result.getMessage().contains(MULTIPLE_REPO_ROOTS));
    }

    @Test
    public void validateInvalidPath() throws Exception {
        String invalidPath = temp.newFolder("test").toString() + File.separator + "invalid\0name";
        final ValidationResult result = validator.validate(invalidPath);
        Assert.assertEquals(ValidationResult.Result.ERROR, result.getResult());
        assertThat(result.getMessage())
                .startsWith("generic.invalid_char");
    }

    private Path createTempZipFile(int rootCount) throws IOException {
        final Path zipFile = Files.createTempFile("offline-repo", ".zip");
        zipFile.toFile().deleteOnExit();
        try(ZipOutputStream out = new ZipOutputStream(new FileOutputStream(zipFile.toFile()))) {
            for (int i=0; i< rootCount; i++) {
                String root = "root-" + i + "/";
                out.putNextEntry(new ZipEntry(root));
                out.putNextEntry(new ZipEntry(root + "maven-repository/"));
                out.putNextEntry(new ZipEntry(root + "maven-repository/content.txt"));
                byte[] data = "Test content".getBytes();
                out.write(data, 0, data.length);
                out.closeEntry();
            }
        }
        return zipFile;
    }
}
