package com.atlassian.bitbucket.mesh.git;

import com.atlassian.bitbucket.mesh.repository.Repository;
import com.atlassian.bitbucket.mesh.rpc.v1.RpcOsFile;
import com.atlassian.bitbucket.mesh.rpc.v1.RpcUploadFileRequest;
import com.atlassian.bitbucket.mesh.util.BuilderSupport;
import com.google.protobuf.Timestamp;

import javax.annotation.Nonnull;
import java.time.Instant;

import static com.google.common.base.Preconditions.checkState;
import static java.util.Objects.requireNonNull;

public class UploadFileParameters {

    private final Instant lastModifiedTime;
    private final String path;
    private final Repository repository;
    private final long size;
    private final UploadType type;

    private UploadFileParameters(Builder builder) {
        checkState(builder.size != -1L, "size is not set");
        lastModifiedTime = requireNonNull(builder.lastModifiedTime, "lastModifiedTime");
        path = builder.path;
        repository = builder.repository;
        size = builder.size;
        type = builder.type;
    }

    @Nonnull
    public Instant getLastModifiedTime() {
        return lastModifiedTime;
    }

    @Nonnull
    public String getPath() {
        return path;
    }

    @Nonnull
    public Repository getRepository() {
        return repository;
    }

    public long getSize() {
        return size;
    }

    @Nonnull
    public UploadType getType() {
        return type;
    }

    public static class Builder extends BuilderSupport {

        private final String path;
        private final Repository repository;
        private final UploadType type;

        private Instant lastModifiedTime;
        private long size;

        public Builder(@Nonnull Repository repository, @Nonnull UploadType type, @Nonnull String path) {
            this.path = requireNonNull(path, "path");
            this.repository = requireNonNull(repository, "repository");
            this.type = requireNonNull(type, "type");

            size = -1L;
        }

        public Builder(@Nonnull Repository repository, @Nonnull RpcUploadFileRequest request) {
            requireNonNull(request, "request");

            this.repository = requireNonNull(repository, "repository");

            RpcOsFile file = request.getFile();
            path = requireNonBlank(file.getPath().toStringUtf8(), "path");
            type = UploadType.fromRpc(request.getType());
            size = file.getSize();
            if (file.hasLastModified()) {
                lastModifiedTime = toInstant(file.getLastModified());
            }
        }

        @Nonnull
        public UploadFileParameters build() {
            return new UploadFileParameters(this);
        }

        @Nonnull
        public Builder lastModifiedTime(@Nonnull Instant value) {
            lastModifiedTime = requireNonNull(value, "lastModifiedTime");
            return this;
        }

        @Nonnull
        public Builder size(long value) {
            size = value;
            return this;
        }

        private static Instant toInstant(Timestamp timestamp) {
            return Instant.ofEpochSecond(timestamp.getSeconds(), timestamp.getNanos());
        }
    }
}
