package com.atlassian.stash.internal.hook.repository;

import com.atlassian.bitbucket.hook.HookResponse;
import com.atlassian.bitbucket.hook.PreReceiveHook;
import com.atlassian.bitbucket.hook.repository.PreReceiveRepositoryHook;
import com.atlassian.bitbucket.hook.repository.RepositoryHookContext;
import com.atlassian.bitbucket.repository.RefChange;
import com.atlassian.bitbucket.repository.Repository;
import com.atlassian.bitbucket.setting.Settings;
import com.atlassian.bitbucket.util.Timer;
import com.atlassian.bitbucket.util.TimerUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Nonnull;
import java.util.Collection;

/**
 * Converts a single {@link PreReceiveHook} to multiple repository {@link PreReceiveRepositoryHook}.
 */
public class PreReceiveRepositoryHookAdapter implements PreReceiveHook {

    private static final Logger log = LoggerFactory.getLogger(PreReceiveRepositoryHookAdapter.class);

    private final InternalRepositoryHookService hookService;

    public PreReceiveRepositoryHookAdapter(InternalRepositoryHookService hookService) {
        this.hookService = hookService;
    }

    @Override
    public boolean onReceive(@Nonnull final Repository repository, @Nonnull final Collection<RefChange> refChanges, @Nonnull final HookResponse hookResponse) {
        return hookService.visitEnabledHooks(repository, PreReceiveRepositoryHook.class, new RepositoryHookSettingsCallback<PreReceiveRepositoryHook>() {
            @Override
            public boolean visit(@Nonnull String key, @Nonnull PreReceiveRepositoryHook hook, @Nonnull Settings settings) {
                try (Timer timer = TimerUtils.start(hook.getClass().getName() + "#onReceive")) {
                    // Stop on first unaccepted hook
                    if (!hook.onReceive(new RepositoryHookContext(repository, settings), refChanges, hookResponse)) {
                        return false;
                    }
                } catch (RuntimeException e) {
                    hookResponse.err().println("Hook " + hook.getClass().getName() + " failed. Error: ");
                    hookResponse.err().println(e.getMessage());
                    log.warn("Receive Hook {} failed.", hook.getClass().getName(), e);
                    // Don't rethrow as otherwise this will be double-logged (and return useless info to the client)
                    return false;
                }
                return true;
            }
        });
    }
}
