package com.atlassian.stash.internal.scm.git.merge;

import com.atlassian.bitbucket.i18n.I18nService;
import com.atlassian.bitbucket.validation.ArgumentValidationException;
import com.google.common.collect.ImmutableMap;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;

import static java.util.Objects.requireNonNull;
import static java.util.stream.Collectors.toList;

/**
 * @since 4.9
 */
public class MapMergeStrategyFactory implements MergeStrategyFactory {

    private final I18nService i18nService;
    private final Map<GitMergeStrategy, MergeStrategy> strategies;

    public MapMergeStrategyFactory(I18nService i18nService, Map<GitMergeStrategy, MergeStrategy> strategies) {
        this.i18nService = i18nService;
        this.strategies = ImmutableMap.copyOf(strategies);

        //Sanity check for the future
        List<GitMergeStrategy> missingStrategies = Arrays.stream(GitMergeStrategy.values())
                .filter(((Predicate<GitMergeStrategy>) strategies::containsKey).negate())
                .collect(toList());
        if (!missingStrategies.isEmpty()) {
            throw new IllegalStateException("One or more strategies have not been registered: " + missingStrategies);
        }
    }

    @Nonnull
    @Override
    public MergeStrategy create(@Nonnull GitMergeStrategy strategy) {
        //This can't miss; the constructor ensures every strategy is mapped
        return strategies.get(requireNonNull(strategy));
    }

    @Nonnull
    @Override
    public MergeStrategy createById(@Nullable String strategyId) {
        return strategyId == null ?
                create(GitMergeStrategy.NO_FF) :
                create(GitMergeStrategy.fromId(strategyId)
                        .orElseThrow(() -> new ArgumentValidationException(
                                i18nService.createKeyedMessage("bitbucket.git.merge.unsupportedstrategy",
                                        strategyId, getSupportedStrategies()))
                        ));
    }

    private List<String> getSupportedStrategies() {
        return strategies.keySet().stream()
                .map(GitMergeStrategy::getId)
                .collect(toList());
    }
}
