/*
 * JBoss, Home of Professional Open Source.
 * Copyright 2023 Red Hat, Inc., and individual 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.apache.commons.lang3.SystemUtils;
import org.jboss.installer.core.LanguageUtils;
import org.jboss.installer.core.ValidationResult;
import org.jboss.installer.postinstall.task.CredentialStoreConfig;
import org.jboss.installer.test.utils.MockLanguageUtils;
import org.junit.Assume;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;

import java.io.File;
import java.nio.file.Path;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertEquals;

public class CredentialStoreValidatorTest {

    private final LanguageUtils langUtils = new MockLanguageUtils();

    @Rule
    public TemporaryFolder temp = new TemporaryFolder();

    @Test
    public void nonExistingParentWindows() throws Exception {
        Assume.assumeTrue(SystemUtils.IS_OS_WINDOWS);
        final CredentialStoreValidator credentialStoreValidator = new CredentialStoreValidator(langUtils, Path.of("."));

        final CredentialStoreConfig config = new CredentialStoreConfig(
                "test-store",
                null,
                "x:\\idontexist",
                "password"
        );
        final ValidationResult result = credentialStoreValidator.validate(config);
        assertEquals(ValidationResult.Result.ERROR, result.getResult());
        assertThat(result.getMessage())
                .startsWith("credential_store.path.no.write.permission");
    }

    @Test
    public void nonWrittableParentLinux() throws Exception {
        Assume.assumeFalse(SystemUtils.IS_OS_WINDOWS);
        final CredentialStoreValidator credentialStoreValidator = new CredentialStoreValidator(langUtils, Path.of("."));

        final Path file = temp.newFolder("test").toPath();
        file.toFile().setWritable(false);
        try {
            final CredentialStoreConfig config = new CredentialStoreConfig(
                    "test-store",
                    null,
                    file.resolve("foo").toString(),
                    "password"
            );
            final ValidationResult result = credentialStoreValidator.validate(config);
            assertEquals(ValidationResult.Result.ERROR, result.getResult());
            assertThat(result.getMessage())
                    .startsWith("credential_store.path.no.write.permission");
        } finally {
            file.toFile().setWritable(true);
        }
    }

    @Test
    public void existingDirectory() throws Exception {
        final CredentialStoreValidator credentialStoreValidator = new CredentialStoreValidator(langUtils, Path.of("."));

        final Path file = temp.newFolder("test").toPath();

        final CredentialStoreConfig config = new CredentialStoreConfig(
                "test-store",
                null,
                file.toString(),
                "password"
        );
        final ValidationResult result = credentialStoreValidator.validate(config);
        assertEquals(ValidationResult.Result.ERROR, result.getResult());
        assertThat(result.getMessage())
                .startsWith("credential_store.path.is.directory");
    }

    @Test
    public void nonExistingFile() throws Exception {
        final CredentialStoreValidator credentialStoreValidator = new CredentialStoreValidator(langUtils, Path.of("."));

        final Path file = temp.newFolder("test").toPath();

        final CredentialStoreConfig config = new CredentialStoreConfig(
                "test-store",
                null,
                file.resolve("foo").toString(),
                "bar"
        );
        final ValidationResult result = credentialStoreValidator.validate(config);
        assertThat(result)
                .isIn(ValidationResult.ok(), ValidationResult.warning("cred-store.path_too_long_warn"));
    }

    @Test
    public void pathContainsInvalidCharacter() throws Exception {
        final CredentialStoreValidator credentialStoreValidator = new CredentialStoreValidator(langUtils, Path.of("."));

        final Path file = temp.newFolder("test").toPath();

        final CredentialStoreConfig config = new CredentialStoreConfig(
                "test-store",
                null,
                file + File.separator + "foo\0bar",
                "password"
        );
        final ValidationResult result = credentialStoreValidator.validate(config);
        assertEquals(ValidationResult.Result.ERROR, result.getResult());
        assertThat(result.getMessage())
                .startsWith("cred-store.invalid_char");
    }

    @Test
    public void pathIsNull() throws Exception {
        final CredentialStoreValidator credentialStoreValidator = new CredentialStoreValidator(langUtils, Path.of("."));

        final CredentialStoreConfig config = new CredentialStoreConfig(
                "test-store",
                null,
                null,
                "password"
        );
        final ValidationResult result = credentialStoreValidator.validate(config);
        assertEquals(ValidationResult.Result.ERROR, result.getResult());
        assertThat(result.getMessage())
                .startsWith("credential_store.ic.error");
    }

    @Test
    public void pathIsEmpty() throws Exception {
        final CredentialStoreValidator credentialStoreValidator = new CredentialStoreValidator(langUtils, Path.of("."));

        final CredentialStoreConfig config = new CredentialStoreConfig(
                "test-store",
                null,
                "",
                "password"
        );
        final ValidationResult result = credentialStoreValidator.validate(config);
        assertEquals(ValidationResult.Result.ERROR, result.getResult());
        assertThat(result.getMessage())
                .startsWith("credential_store.ic.error");
    }

    @Test
    public void passwordIsNull() throws Exception {
        final CredentialStoreValidator credentialStoreValidator = new CredentialStoreValidator(langUtils, Path.of("."));

        final CredentialStoreConfig config = new CredentialStoreConfig(
                "test-store",
                null,
                "foo",
                null
        );
        final ValidationResult result = credentialStoreValidator.validate(config);
        assertEquals(ValidationResult.Result.ERROR, result.getResult());
        assertThat(result.getMessage())
                .startsWith("credential_store.ic.error");
    }

    @Test
    public void passwordEmpty() throws Exception {
        final CredentialStoreValidator credentialStoreValidator = new CredentialStoreValidator(langUtils, Path.of("."));

        final CredentialStoreConfig config = new CredentialStoreConfig(
                "test-store",
                null,
                "foo",
                ""
        );
        final ValidationResult result = credentialStoreValidator.validate(config);
        assertEquals(ValidationResult.Result.ERROR, result.getResult());
        assertThat(result.getMessage())
                .startsWith("credential_store.ic.error");
    }

    @Test
    public void storeNameIsNull() throws Exception {
        final CredentialStoreValidator credentialStoreValidator = new CredentialStoreValidator(langUtils, Path.of("."));

        final CredentialStoreConfig config = new CredentialStoreConfig(
                null,
                null,
                "foo",
                "bar"
        );
        final ValidationResult result = credentialStoreValidator.validate(config);
        assertEquals(ValidationResult.Result.ERROR, result.getResult());
        assertThat(result.getMessage())
                .startsWith("credential_store.ic.error");
    }

    @Test
    public void storeNameEmpty() throws Exception {
        final CredentialStoreValidator credentialStoreValidator = new CredentialStoreValidator(langUtils, Path.of("."));

        final CredentialStoreConfig config = new CredentialStoreConfig(
                "",
                null,
                "foo",
                "bar"
        );
        final ValidationResult result = credentialStoreValidator.validate(config);
        assertEquals(ValidationResult.Result.ERROR, result.getResult());
        assertThat(result.getMessage())
                .startsWith("credential_store.ic.error");
    }
}