package ru.yandex.qe.dispenser.ws.quota.request.workflow.service;

import java.util.Map;
import java.util.Set;

import javax.annotation.ParametersAreNonnullByDefault;

import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.SetMultimap;

import ru.yandex.qe.dispenser.domain.exception.SingleMessageException;
import ru.yandex.qe.dispenser.ws.quota.request.workflow.context.RequestContext;

import static org.apache.commons.lang3.StringUtils.trimToEmpty;

@ParametersAreNonnullByDefault
public class QloudPropertyValidator extends SimpleServicePropertyValidator {
    private static final String INSTALLATION = "installation";
    private static final String SEGMENT = "segment";
    private static final String PROJECT = "project";

    private static final Set<String> REQUIRED_PROPERTIES = ImmutableSet.of(INSTALLATION, SEGMENT, PROJECT);
    private static final SetMultimap<String, String> SEGMENTS_BY_INSTALLATION = ImmutableSetMultimap.<String, String>builder()
            .putAll("qloud",
                    "april", "cocs", "common-dev", "common-rtc", "common-storage", "gateway", "infra", "jupyter-storage", "mtn", "nirvana-storage", "routers", "common-ci")
            .putAll("qloud-ext",
                    "browser", "browser-mobile", "common", "common-ci", "common-oort", "common-storage", "common-zen", "dogma", "gateway",
                    "mail", "mail-perf", "metrika", "outsource", "outsource-storage", "personal", "personal-storage", "qabs", "routers", "security",
                    "sox", "voicetech", "zen", "zen-perf", "zen-perfomance")
            .build();

    public QloudPropertyValidator() {
        super(REQUIRED_PROPERTIES);
    }

    @Override
    public void validateAdditionalPropertiesOnCreate(final RequestContext context, final Map<String, String> additionalProperties) {
        super.validateAdditionalPropertiesOnCreate(context, additionalProperties);
        validateSegmentAndInstallation(additionalProperties);
    }

    @Override
    public void validateAdditionalPropertiesOnUpdate(final RequestContext context, final Map<String, String> additionalProperties,
                                                     final Map<String, String> currentAdditionalProperties) {
        super.validateAdditionalPropertiesOnUpdate(context, additionalProperties, currentAdditionalProperties);
        if (context.getCampaign() == null || !context.getCampaign().isAllowedModificationOnMissingAdditionalFields()) {
            // Base case - do usual validation
            validateSegmentAndInstallation(additionalProperties);
            return;
        }
        // Special flag is set
        final boolean hasCurrentInstallation = currentAdditionalProperties.containsKey(INSTALLATION)
                && !trimToEmpty(currentAdditionalProperties.get(INSTALLATION)).isEmpty();
        final boolean hasInstallation = additionalProperties.containsKey(INSTALLATION)
                && !trimToEmpty(additionalProperties.get(INSTALLATION)).isEmpty();
        final boolean hasCurrentSegment = currentAdditionalProperties.containsKey(SEGMENT)
                && !trimToEmpty(currentAdditionalProperties.get(SEGMENT)).isEmpty();
        final boolean hasSegment = additionalProperties.containsKey(INSTALLATION)
                && !trimToEmpty(additionalProperties.get(INSTALLATION)).isEmpty();
        if (hasInstallation && hasSegment) {
            // Installation and segment are both present - do usual validation
            validateSegmentAndInstallation(additionalProperties);
            return;
        }
        if (hasInstallation && !hasCurrentSegment) {
            // Installation is present, segment is missing, current segment value is also missing, validate installation only
            validateInstallation(additionalProperties);
            return;
        }
        if (!hasInstallation && !hasSegment && !hasCurrentInstallation && !hasCurrentSegment) {
            // No segment and installation is present, current values are also missing, nothing to validate
            return;
        }
        // Otherwise - it's invalid update
        if (!hasInstallation && hasSegment) {
            // Can not set segment without installation
            throw SingleMessageException.illegalArgument("qloud.segment.cannot.be.set.without.installation");
        }
        // can not overwrite with empty values
        throw SingleMessageException.illegalArgument("qloud.installation.and.segment.must.be.selected");
    }

    private void validateInstallation(final Map<String, String> additionalProperties) {
        final String installation = additionalProperties.get(INSTALLATION);
        if (!SEGMENTS_BY_INSTALLATION.containsKey(installation)) {
            throw SingleMessageException.illegalArgument("qloud.request.has.unknown.installation", installation);
        }
    }

    private void validateSegmentAndInstallation(final Map<String, String> additionalProperties) {
        final String installation = additionalProperties.get(INSTALLATION);
        if (SEGMENTS_BY_INSTALLATION.containsKey(installation)) {
            final String segment = additionalProperties.get(SEGMENT);

            final Set<String> allowedSegments = SEGMENTS_BY_INSTALLATION.get(installation);
            if (!allowedSegments.contains(segment)) {
                throw SingleMessageException.illegalArgument("qloud.request.has.unknown.segment.for.installation", segment, installation);
            }
        } else {
            throw SingleMessageException.illegalArgument("qloud.request.has.unknown.installation", installation);
        }
    }

}
