package com.atlassian.stash.internal.check;

import com.atlassian.bitbucket.scm.ScmRequest;
import com.atlassian.bitbucket.scm.ScmRequestCheck;
import com.atlassian.bitbucket.scm.ScmRequestCheckModuleDescriptor;
import com.atlassian.bitbucket.scm.ScmRequestCheckService;
import com.atlassian.plugin.PluginAccessor;
import com.atlassian.plugin.spring.AvailableToPlugins;
import com.atlassian.stash.internal.AbstractService;
import com.atlassian.stash.internal.annotation.Unsecured;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.util.stream.Stream;

import static com.atlassian.bitbucket.util.ModuleDescriptorUtils.toSortedModules;
import static java.util.stream.Collectors.toList;

@AvailableToPlugins(ScmRequestCheckService.class)
@Service("scmRequestCheckService")
@Transactional(propagation = Propagation.SUPPORTS)
public class ScmRequestCheckServiceImpl extends AbstractService implements ScmRequestCheckService {

    private final PluginAccessor pluginAccessor;
    private final LicensingCheck licensingCheck;

    @Autowired
    public ScmRequestCheckServiceImpl(PluginAccessor pluginAccessor, LicensingCheck licensingCheck) {
        this.pluginAccessor = pluginAccessor;
        this.licensingCheck = licensingCheck;
    }

    @Override
    @Unsecured("Validating whether an SCM request can proceed does not require a specific permission")
    public boolean checkActionAllowed(ScmRequest request) throws IOException {
        // specifically check the license up front (not pluggable to discourage tampering)
        Iterable<ScmRequestCheck> requestChecks = Stream.concat(
                Stream.of(licensingCheck),
                toSortedModules(pluginAccessor.getEnabledModuleDescriptorsByClass(ScmRequestCheckModuleDescriptor.class)))
                .collect(toList());

        for (ScmRequestCheck check : requestChecks) {
            if (!check.check(request)) {
                return false;
            }
        }

        return true;
    }
}
