/*
 * JBoss, Home of Professional Open Source.
 * Copyright 2021 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.jboss.installer.core.LanguageUtils;
import org.jboss.installer.core.ValidationResult;
import org.jboss.installer.postinstall.task.DatasourceConfig;

import java.util.List;

public class DatasourceValidator {

    public static final String INVALID_JNDI_KEY = "datasource.validation.invalid_jndi";
    public static final String EMPTY_FIELDS_KEY = "datasource.validation.empty_fields";
    public static final String INVALID_POOL_SIZE_KEY = "datasource.validation.invalid_pool_sizes";
    public static final String DS_NAME_WHITESPACES_KEY = "datasource.validation.datasource_whitespaces";
    public static final String DUPLICATE_PROPERTY_KEY = "datasource.validation.duplicate_property";
    private final LanguageUtils languageUtils;

    public DatasourceValidator(LanguageUtils langUtils) {
        this.languageUtils = langUtils;
    }

    public ValidationResult validate(DatasourceConfig config) {
        if (areCommonFieldsEmpty(config) || areDatasourceTypeFieldsEmpty(config) || areSecurityTypeFieldsEmpty(config)) {
            return ValidationResult.error(languageUtils.getString(EMPTY_FIELDS_KEY));
        }
        if (!isJndiNameValid(config.getJndiName())) {
            return ValidationResult.error(languageUtils.getString(INVALID_JNDI_KEY));
        }
        if (!isPoolSizeValid(config)) {
            return ValidationResult.error(languageUtils.getString(INVALID_POOL_SIZE_KEY));
        }
        if (config.getDsName().contains(" ")) {
            return ValidationResult.error(languageUtils.getString(DS_NAME_WHITESPACES_KEY));
        }
        if (config.getXaProperties() != null && !arePropertyKeysUnique(config.getXaProperties())) {
            return ValidationResult.error(languageUtils.getString(DUPLICATE_PROPERTY_KEY));
        }

        return ValidationResult.ok();
    }

    private boolean areCommonFieldsEmpty(DatasourceConfig config) {
        return isEmpty(config.getDsName()) ||
                isEmpty(config.getMinPool()) ||
                isEmpty(config.getMaxPool()) ||
                isEmpty(config.getJndiName());
    }

    private static boolean isEmpty(String value) {
        return value == null || value.isEmpty();
    }

    private boolean isPoolSizeValid(DatasourceConfig config) {
        return Integer.parseInt(config.getMinPool()) <= Integer.parseInt(config.getMaxPool());
    }

    private boolean isJndiNameValid(String jndiName) {
        return jndiName.startsWith("java:/") || jndiName.startsWith("java:jboss/");
    }

    private boolean areDatasourceTypeFieldsEmpty(DatasourceConfig config) {
        if (config.getXaProperties() != null) {
            return isEmpty(config.getXaUsername()) ||
                    config.getXaProperties().stream()
                            .anyMatch(xaProperty -> isEmpty(xaProperty.getKey()) || isEmpty(xaProperty.getValue()));
        } else {
            return isEmpty(config.getConnectionUrl());
        }
    }

    private boolean areSecurityTypeFieldsEmpty(DatasourceConfig config) {
        if (config.getSecurityDomain() != null) {
            return isEmpty(config.getSecurityDomain());
        } else {
            return isEmpty(config.getDsUsername());
        }
    }

    private boolean arePropertyKeysUnique(List<DatasourceConfig.XaProperty> properties) {
        return properties.size() == properties.stream().map(DatasourceConfig.XaProperty::getKey).distinct().count();
    }
}
