package com.atlassian.bitbucket.mesh.git.pull;

import com.atlassian.bitbucket.mesh.git.GitAgent;
import com.atlassian.bitbucket.mesh.git.ref.RefUpdate;
import com.atlassian.bitbucket.mesh.repository.BitbucketServerRepository;
import com.atlassian.bitbucket.mesh.repository.Repository;
import com.atlassian.bitbucket.mesh.transaction.ReferenceTransaction;
import com.atlassian.bitbucket.mesh.transaction.ReferenceTransactionListener;
import com.atlassian.bitbucket.mesh.transaction.ReferenceTransactionState;
import com.atlassian.bitbucket.mesh.util.ShaUtils;

import javax.annotation.Nonnull;
import java.util.function.Predicate;

import static com.atlassian.bitbucket.mesh.git.GitConstants.PATH_DARK_REFS;
import static com.atlassian.bitbucket.mesh.git.GitConstants.PATH_STASH_REFS;

public class DarkReferenceTransactionListener implements ReferenceTransactionListener {

    private final GitAgent agent;

    public DarkReferenceTransactionListener(GitAgent agent) {
        this.agent = agent;
    }

    @Override
    public void onReferenceTransaction(@Nonnull ReferenceTransaction referenceTransaction) {
        if (referenceTransaction.getState() != ReferenceTransactionState.PREPARED ||
                referenceTransaction.isRejected()) {
            return;
        }

        enableReflogsForDarkPullRequestRefs(referenceTransaction);
    }

    private void enableReflogsForDarkPullRequestRefs(ReferenceTransaction referenceTransaction) {
        Repository repository = referenceTransaction.getRepository();
        boolean isBitbucketServerRepository = repository instanceof BitbucketServerRepository;
        String darkPrefix = isBitbucketServerRepository ? PATH_STASH_REFS : PATH_DARK_REFS;
        //For Bitbucket Server repositories, only enable the reflog when a new PR ref is created. This is enough as
        //there is no vacuuming for those repositories.
        //For Managed repositories, reflogs can be vacuumed and removed and on further updates, they have to be enabled
        //again.
        Predicate<RefUpdate> shouldEnableReflog = isBitbucketServerRepository ?
                ru -> ShaUtils.isNull(ru.getOldHash()) :
                ru -> !ShaUtils.isNull(ru.getNewHash());
        //Enable the reflog for any dark pull request ref being created
        referenceTransaction.getRefUpdates().stream()
                .filter(ru -> ru.getRefId().startsWith(darkPrefix) && shouldEnableReflog.test(ru))
                .map(RefUpdate::getRefId)
                .forEach(refId -> agent.enableReflog(repository, refId));
    }
}
