package com.atlassian.bitbucket.branch.automerge;

import com.atlassian.bitbucket.audit.AuditEntry;
import com.atlassian.bitbucket.audit.AuditEntryBuilder;
import com.atlassian.bitbucket.audit.AuditEntryConverter;
import com.atlassian.bitbucket.repository.Branch;
import com.atlassian.bitbucket.repository.RefChange;
import com.google.common.collect.ImmutableMap;

import javax.annotation.Nonnull;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.atlassian.bitbucket.util.AuditUtils.toJson;
import static com.atlassian.bitbucket.util.AuditUtils.toProjectAndRepositoryString;
import static com.atlassian.bitbucket.util.MoreStreams.streamIterable;

/**
 * Converts an {@link AutomaticMergeEvent} to an {@link AuditEntry} for inclusion in the audit log.
 * <p>
 * This class appears in the API because it must be attached to an annotation on {@link AutomaticMergeEvent}. It is
 * <i>not</i> considered part of the API, however, and offers no compatibility guarantees. Plugin developers should
 * not use this class.
 */
public class AutomaticMergeEventConverter implements AuditEntryConverter<AutomaticMergeEvent> {

    private static Function<RefChange, Map<String, Object>> REF_CHANGE_TO_MAP =
        change -> ImmutableMap.<String, Object>of(
                        "ref", change.getRef().getId(),
                        "from", change.getFromHash(),
                        "to", change.getToHash());

    @Nonnull
    @Override
    public AuditEntry convert(@Nonnull AutomaticMergeEvent event, AuditEntryBuilder builder) {
        List<Map<String, Object>> refChanges = event.getRefChanges().stream()
                .map(REF_CHANGE_TO_MAP).collect(Collectors.toList());

        List<String> mergePaths = streamIterable(event.getMergePath())
                .map(Branch::getId).collect(Collectors.toList());

        ImmutableMap.Builder<String, Object> mapBuilder = ImmutableMap.<String, Object>builder()
                .put("refChanges", refChanges)
                .put("mergePath", mergePaths);

        if (event instanceof AutomaticMergeStoppedEvent) {
            AutomaticMergeStoppedEvent stoppedEvent = (AutomaticMergeStoppedEvent) event;
            mapBuilder.put("reason", stoppedEvent.getReason());
        }

        return builder.action(event.getClass())
                .timestamp(new Date())
                .details(toJson(mapBuilder.build()))
                .user(event.getUser())
                .target(toProjectAndRepositoryString(event.getRepository()))
                .repository(event.getRepository())
                .build();
    }
}

