package com.atlassian.bitbucket.mesh.transaction;

import com.atlassian.bitbucket.mesh.git.binary.GitBinary;
import com.atlassian.bitbucket.mesh.git.ref.Branch;
import com.atlassian.bitbucket.mesh.rpc.v1.RpcProposedRefUpdate;
import com.atlassian.bitbucket.mesh.rpc.v1.RpcTransaction;
import com.atlassian.bitbucket.mesh.rpc.v1.RpcUpdateRefsRequest;
import com.atlassian.bitbucket.mesh.util.ShaUtils;
import com.google.protobuf.ByteString;

import javax.annotation.Resource;
import java.nio.file.Files;
import java.nio.file.Path;

import static com.atlassian.bitbucket.mesh.git.GitConstants.PATH_LOGS;

/**
 * Similar to {@link TransactUpdateRefsTest}, but verifies that pull request refs (including dark refs) are replicated
 * correctly, and that reflogs are created for newly created dark refs.
 */
public class TransactUpdatePullRequestRefsTest extends AbstractPreparedActionWriteTest {

    @Resource
    private GitBinary gitBinary;

    @Override
    protected RpcTransaction.Builder createTransaction(RpcTransaction.Builder builder) {
        return builder.setUpdateRefs(RpcUpdateRefsRequest.newBuilder()
                .addRefUpdates(RpcProposedRefUpdate.newBuilder()
                        .setRefId(ByteString.copyFromUtf8("refs/pull-requests/42/from"))
                        .setNewHash("d6edcbf924697ab811a867421dab60d954ccad99")
                        .setOldHash(ShaUtils.NULL_SHA1))
                .addRefUpdates(RpcProposedRefUpdate.newBuilder()
                        .setRefId(ByteString.copyFromUtf8("dark-refs/pull-requests/42/from"))
                        .setNewHash("d6edcbf924697ab811a867421dab60d954ccad99")
                        .setOldHash(ShaUtils.NULL_SHA1))
                .setRepository(repository.getId())
                .setTransactional(true));
    }

    @Override
    protected RpcTransaction.Builder createTransactionThatTriggersError(RpcTransaction.Builder builder) {
        return builder.setUpdateRefs(RpcUpdateRefsRequest.newBuilder()
                .addRefUpdates(RpcProposedRefUpdate.newBuilder()
                        .setRefId(ByteString.copyFromUtf8("refs/pull-requests/42/from"))
                        .setNewHash("aaaaaaaaaabbbbbbbbbbccccccccccdddddddddd") //does not exist
                        .setOldHash(ShaUtils.NULL_SHA1))
                .addRefUpdates(RpcProposedRefUpdate.newBuilder()
                        .setRefId(ByteString.copyFromUtf8("dark-refs/pull-requests/42/from"))
                        .setNewHash("aaaaaaaaaabbbbbbbbbbccccccccccdddddddddd") //does not exist
                        .setOldHash(ShaUtils.NULL_SHA1))
                .setRepository(repository.getId())
                .setTransactional(true));
    }

    @Override
    protected boolean isApplied(RpcTransaction transaction) {
        for (RpcProposedRefUpdate updateRef : transaction.getUpdateRefs().getRefUpdatesList()) {
            Branch branch = agent.resolveBranch(repository, updateRef.getRefId().toStringUtf8(), true);
            if (branch == null && !ShaUtils.isNull(updateRef.getNewHash())) {
                //Branch was not resolved, but should have been created or updated
                return false;
            }
            if (branch != null) {
                if (ShaUtils.hashesMatch(branch.getLatestCommit(), updateRef.getNewHash())) {
                    if (branch.getId().startsWith("dark-refs/")) {
                        Path reflog = repository.getPath().resolve(PATH_LOGS).resolve(branch.getId());
                        if (!Files.exists(reflog)) {
                            //Dark ref was created, but no reflog was created
                            return false;
                        }
                    }
                } else {
                    //Branch was resolved, but does not match the expected hash
                    return false;
                }
            }
        }
        return true;
    }
}
