package com.atlassian.bitbucket.mesh.transaction;

import com.atlassian.bitbucket.mesh.io.MoreFiles;
import com.atlassian.bitbucket.mesh.repository.ManagedRepository;
import com.atlassian.bitbucket.mesh.repository.SharedObjectsRepository;
import com.atlassian.bitbucket.mesh.rpc.v1.*;
import com.google.protobuf.ByteString;
import org.junit.After;
import org.junit.Before;

import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;

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

public class TransactDeletePullRequestTest extends AbstractPreparedActionWriteTest {

    private static final String PR_FROM_HASH = "d6edcbf924697ab811a867421dab60d954ccad99";
    private static final long PR_ID = 823L;

    private Path darkFromRef;
    private Path publicFromRef;
    private Path reflog;
    private Path sharedPublicFromRef;
    private Path sharedReflog;

    @Before
    public void setUp() throws IOException {
        ManagedRepository managed = repository;
        Path fromRef = Paths.get(PATH_PULL_REQUESTS, Long.toString(PR_ID), "from");
        publicFromRef = repository.getPath().resolve(PATH_REFS).resolve(fromRef);
        darkFromRef = repository.getPath().resolve(PATH_DARK_REFS).resolve(fromRef);

        //Create the public and the dark refs
        MoreFiles.mkdir(publicFromRef.getParent());
        MoreFiles.write(publicFromRef, PR_FROM_HASH);
        MoreFiles.mkdir(darkFromRef.getParent());
        MoreFiles.write(darkFromRef, PR_FROM_HASH);

        //Create the public ref in shared-objects as well
        SharedObjectsRepository shared = managed.getSharedObjects();
        Path namespace = Paths.get("r", managed.getLocalId());
        sharedPublicFromRef = shared.getPath().resolve(PATH_REFS).resolve(namespace).resolve(PATH_REFS).resolve(fromRef);
        MoreFiles.mkdir(sharedPublicFromRef.getParent());
        MoreFiles.write(sharedPublicFromRef, PR_FROM_HASH);

        //Create the stash-refs reflog file in the repo and shared-objects
        reflog = MoreFiles.resolve(repository.getPath(), PATH_LOGS, PATH_DARK_REFS).resolve(fromRef);
        sharedReflog = shared.getReflogDir(managed).resolve(PATH_DARK_REFS).resolve(fromRef);
        MoreFiles.mkdir(reflog.getParent());
        MoreFiles.touch(reflog);
        MoreFiles.mkdir(sharedReflog.getParent());
        MoreFiles.touch(sharedReflog);
    }

    @After
    public void tearDown() {
        MoreFiles.deleteQuietly(darkFromRef.getParent());
        MoreFiles.deleteQuietly(publicFromRef.getParent());
        MoreFiles.deleteQuietly(sharedPublicFromRef.getParent());
        MoreFiles.deleteQuietly(reflog.getParent());
        MoreFiles.deleteQuietly(sharedReflog.getParent());
    }

    @Override
    protected RpcTransaction.Builder createTransaction(RpcTransaction.Builder builder) {
        return builder.setDeletePullRequest(RpcDeletePullRequestRequest.newBuilder()
                .setPullRequest(RpcPullRequest.newBuilder()
                        .setId(PR_ID)
                        .setFromRef(RpcPullRequestRef.newBuilder()
                                .setId(ByteString.copyFromUtf8("refs/heads/basic_branching"))
                                .setLatestCommit(PR_FROM_HASH)
                                .setRepository(repository.getId()))
                        .setState(RpcPullRequestState.PR_STATE_DECLINED)
                        .setToRef(RpcPullRequestRef.newBuilder()
                                .setId(ByteString.copyFromUtf8("refs/heads/master"))
                                .setLatestCommit("0a943a29376f2336b78312d99e65da17048951db")
                                .setRepository(repository.getId()))
                        .setVersion(3)));
    }

    @Override
    protected RpcTransaction.Builder createTransactionThatTriggersError(RpcTransaction.Builder builder) {
        return builder.setDeletePullRequest(RpcDeletePullRequestRequest.newBuilder()
                .setPullRequest(RpcPullRequest.newBuilder()
                        .setId(PR_ID)
                        .setFromRef(RpcPullRequestRef.newBuilder()
                                .setId(ByteString.copyFromUtf8("refs/heads/basic_branching"))
                                .setLatestCommit(PR_FROM_HASH)
                                .setRepository("does-not-exist")) //invalid source repository
                        .setState(RpcPullRequestState.PR_STATE_DECLINED)
                        .setToRef(RpcPullRequestRef.newBuilder()
                                .setId(ByteString.copyFromUtf8("refs/heads/master"))
                                .setLatestCommit("0a943a29376f2336b78312d99e65da17048951db")
                                .setRepository(repository.getId()))
                        .setVersion(3)));
    }

    @Override
    protected boolean isApplied(RpcTransaction transaction) {
        return !(MoreFiles.dirExists(publicFromRef.getParent()) ||
                MoreFiles.dirExists(darkFromRef.getParent()) ||
                MoreFiles.dirExists(sharedReflog.getParent()) ||
                MoreFiles.dirExists(reflog.getParent()));
    }
}
