package org.jboss.installer.validators;

import org.jboss.installer.core.ValidationResult;
import org.jboss.installer.postinstall.task.secdom.CertificateConfig;
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.IOException;
import java.nio.file.Paths;

import static org.jboss.installer.screens.domain.CertificateSecurityDomainPanel.FILTER_VALUE_KEY;
import static org.jboss.installer.screens.domain.CertificateSecurityDomainPanel.MAX_SEGMENT_KEY;
import static org.jboss.installer.screens.domain.CertificateSecurityDomainPanel.ROLES_KEY;
import static org.jboss.installer.screens.domain.CertificateSecurityDomainPanel.START_SEGMENT_KEY;
import static org.jboss.installer.screens.domain.CertificateSecurityDomainPanel.TRUST_STORE_PASSWORD_KEY;
import static org.jboss.installer.screens.domain.CertificateSecurityDomainPanel.TRUST_STORE_PATH_KEY;
import static org.jboss.installer.validators.CertificateSecurityDomainValidator.GENERIC_VALIDATION_EMPTY_FIELD;
import static org.jboss.installer.validators.CertificateSecurityDomainValidator.UNSUPPORTED_X509_FIELD;
import static org.jboss.installer.validators.FileValidator.IS_DIRECTORY_ERROR;
import static org.jboss.installer.validators.FileValidator.NOT_ABSOLUTE_ERROR;
import static org.jboss.installer.validators.FileValidator.NOT_EXISTS_ERROR;
import static org.junit.Assert.assertEquals;

public class CertificateSecurityDomainValidatorTest {

    @Rule
    public TemporaryFolder temp = new TemporaryFolder();

    private final MockLanguageUtils langUtils = new MockLanguageUtils();
    private final CertificateSecurityDomainValidator validator = new CertificateSecurityDomainValidator(langUtils);
    private CertificateConfig config;

    @Before
    public void setUp() throws Exception {
        config = defaultConfig();
    }

    @Test
    public void testDefaultConfigOK() {
        assertEquals(ValidationResult.ok(), validator.validate(config));
    }

    @Test
    public void testPasswordPresentAndNonEmpty() {
        final String expectedError = langUtils.getString(GENERIC_VALIDATION_EMPTY_FIELD, langUtils.getString(TRUST_STORE_PASSWORD_KEY));

        config.setTrustStorePassword("");
        assertEquals(ValidationResult.error(expectedError), validator.validate(config));

        config.setTrustStorePassword(null);
        assertEquals(ValidationResult.error(expectedError), validator.validate(config));
    }

    @Test
    public void testTrustStorePresentExistsAndNonEmpty() {
        final String expectedError = langUtils.getString(GENERIC_VALIDATION_EMPTY_FIELD, langUtils.getString(TRUST_STORE_PATH_KEY));

        config.setTrustStorePath(null);
        assertEquals(ValidationResult.error(expectedError), validator.validate(config));

        config.setTrustStorePath(Paths.get("i", "dont", "exist"));
        assertEquals(ValidationResult.error(NOT_ABSOLUTE_ERROR).getResult(), validator.validate(config).getResult());

        config.setTrustStorePath(Paths.get(temp.toString(), "nonexistent"));
        assertEquals(ValidationResult.error(NOT_EXISTS_ERROR).getResult(), validator.validate(config).getResult());

        config.setTrustStorePath(temp.getRoot().toPath());
        assertEquals(ValidationResult.error(IS_DIRECTORY_ERROR).getResult(), validator.validate(config).getResult());
    }

    @Test
    public void testFilterExpressionPresentAndNonEmpty() {
        final String expectedError = langUtils.getString(GENERIC_VALIDATION_EMPTY_FIELD, langUtils.getString(FILTER_VALUE_KEY));

        config.setFilterExpression("");
        assertEquals(ValidationResult.error(expectedError), validator.validate(config));

        config.setFilterExpression(null);
        assertEquals(ValidationResult.error(expectedError), validator.validate(config));
    }

    @Test
    public void testUnsupportedFilterExpression() {

        config.setFilterExpression("idontexist");
        config.setUseOid(false);
        assertEquals(ValidationResult.error(langUtils.getString(UNSUPPORTED_X509_FIELD, "idontexist")), validator.validate(config));

        config.setFilterExpression("1.2.3");
        config.setUseOid(true);
        assertEquals(ValidationResult.error(langUtils.getString(UNSUPPORTED_X509_FIELD, "1.2.3")), validator.validate(config));

        config.setFilterExpression("CN");
        config.setUseOid(false);
        assertEquals(ValidationResult.ok(), validator.validate(config));
    }

    @Test
    public void testRolesPresentAndNonEmpty() {
        final String expectedError = langUtils.getString(GENERIC_VALIDATION_EMPTY_FIELD, langUtils.getString(ROLES_KEY));

        config.setRoles(new String[]{});
        assertEquals(ValidationResult.error(expectedError), validator.validate(config));

        config.setRoles(null);
        assertEquals(ValidationResult.error(expectedError), validator.validate(config));
    }

    @Test
    public void testMaxSegmentsPresent() {
        final String expectedError = langUtils.getString(GENERIC_VALIDATION_EMPTY_FIELD, langUtils.getString(MAX_SEGMENT_KEY));

        config.setMaximumSegments(null);
        assertEquals(ValidationResult.error(expectedError), validator.validate(config));
    }

    @Test
    public void testStartSegmentsPresent() {
        final String expectedError = langUtils.getString(GENERIC_VALIDATION_EMPTY_FIELD, langUtils.getString(START_SEGMENT_KEY));

        config.setStartSegments(null);
        assertEquals(ValidationResult.error(expectedError), validator.validate(config));
    }

    private CertificateConfig defaultConfig() throws IOException {
        final CertificateConfig certConfig = new CertificateConfig();

        certConfig.setApplicationDomainName("TestSD");
        certConfig.setFilterExpression("2.5.4.3");
        certConfig.setMaximumSegments(1);
        certConfig.setStartSegments(0);
        certConfig.setRoles(new String[]{"Admin", "Guest"});
        certConfig.setTrustStorePath(temp.newFile("store.jks").toPath().toAbsolutePath());
        certConfig.setTrustStorePassword("secret");
        certConfig.setUseOid(true);

        return certConfig;
    }
}