package com.atlassian.bitbucket.internal.mirroring.mirror.webhook;

import com.atlassian.bitbucket.internal.mirroring.mirror.InternalUpstreamService;
import com.atlassian.bitbucket.util.ValidationUtils;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.Nonnull;
import javax.validation.ConstraintViolationException;
import javax.validation.Validator;

import static com.atlassian.bitbucket.internal.mirroring.ConstraintViolationUtils.violationToString;
import static org.slf4j.LoggerFactory.getLogger;

@Component
public class DefaultMirroringWebHookEventHandler implements MirroringWebHookEventHandler {
    private static final Logger log = getLogger(DefaultMirroringWebHookEventHandler.class);

    private final InternalUpstreamService upstreamService;
    private final Validator validator;

    @Autowired
    public DefaultMirroringWebHookEventHandler(InternalUpstreamService upstreamService, Validator validator) {
        this.upstreamService = upstreamService;
        this.validator = validator;
    }

    @Override
    public void handleEvent(@Nonnull String upstreamId, @Nonnull MirroringWebHookEvent event) {
        validate(event);

        event.visit(new AbstractWebHookEventVisitor<Void>() {
            @Override
            public Void accept(ProjectModifiedWebHookEvent event) {
                upstreamService.onProjectModified(upstreamId, event.getProject());
                return null;
            }

            @Override
            public Void accept(RepositoryCreatedWebHookEvent event) {
                upstreamService.onRepositoryCreated(upstreamId, event.getRepository());
                return null;
            }

            @Override
            public Void accept(RepositoryDeletedWebHookEvent event) {
                upstreamService.onRepositoryDeleted(upstreamId, event.getRepository());
                return null;
            }

            @Override
            public Void accept(RepositoryModifiedWebHookEvent event) {
                upstreamService.onRepositoryModified(upstreamId, event.getRepository());
                return null;
            }

            @Override
            public Void accept(RepositoryRefsChangedWebHookEvent event) {
                upstreamService.onRepositoryContentsChanged(upstreamId, event.getRepository(), event.getChanges());
                return null;
            }
        });
    }

    private void validate(@Nonnull MirroringWebHookEvent event) {
        try {
            ValidationUtils.validate(validator, event);
        } catch (ConstraintViolationException e) {
            String constraintsMessage = violationToString(e);
            log.info("Web hook had an unexpected format - ignoring: {}. Error details:",
                    constraintsMessage, e);
            throw e;
        }
    }

}
