package com.atlassian.bitbucket.mesh.repository;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.nio.file.Path;
import java.time.Clock;
import java.time.Instant;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static java.lang.String.format;
import static java.util.Objects.requireNonNull;

public class DefaultWorkTree implements WorkTree {

    private static final Pattern WORK_TREE_ID = Pattern.compile("wt/(?<localId>[0-9]+)");

    private final Clock clock;
    private final Instant expiry;
    private final boolean hasAlternates;
    private final String id;
    private final long localId;
    private final Path path;
    private final Repository repository;

    DefaultWorkTree(@Nonnull Instant expiry, boolean hasAlternates, long localId, @Nonnull Path path,
                    @Nonnull Repository repository) {
        this(Clock.systemDefaultZone(), expiry, hasAlternates, localId, path, repository);
    }

    DefaultWorkTree(Clock clock, @Nonnull Instant expiry, boolean hasAlternates, long localId, @Nonnull Path path,
                    @Nonnull Repository repository) {
        this.clock = clock;
        this.localId = localId;
        this.hasAlternates = hasAlternates;
        this.expiry = requireNonNull(expiry, "expiry");
        this.path = requireNonNull(path, "path");
        this.repository = requireNonNull(repository, "repository");

        id = WorkTree.formatId(localId);
    }

    @Override
    public <T> T accept(@Nonnull RepositoryVisitor<T> visitor) {
        return requireNonNull(visitor, "visitor").visit(this);
    }

    @Nonnull
    @Override
    public Instant getExpiry() {
        return expiry;
    }

    @Nonnull
    @Override
    public String getId() {
        return id;
    }

    @Nonnull
    @Override
    public Path getLfsDir() {
        throw new UnsupportedOperationException("Work trees do not support LFS");
    }

    public long getLocalId() {
        return localId;
    }

    @Override
    public String getParameter(@Nonnull String name) {
        return repository.getParameter(name);
    }

    @Nonnull
    @Override
    public Path getPath() {
        return path;
    }

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

    @Nonnull
    @Override
    public String getSlug() {
        return "wt-" + localId;
    }

    @Nonnull
    @Override
    public Path getWorkTreesDir() {
        throw new UnsupportedOperationException("Work trees do not support creating work trees");
    }

    @Override
    public boolean hasAlternates() {
        return hasAlternates;
    }

    @Override
    public boolean isExpired() {
        return !clock.instant().isBefore(expiry);
    }

    @Override
    public boolean isReadOnly() {
        //work trees can never be read only
        return false;
    }

    @Override
    public void setReadOnly(boolean value) {
        throw new UnsupportedOperationException(format("Trying to set read-only value to '%s' on work tree '%s'",
                value, id));
    }

    @Override
    public String toString() {
        return "Work tree{ID=" + localId +
                ", repository=" + repository +
                '}';
    }

    @Nullable
    static Long parseId(@Nonnull String id) {
        Matcher matcher = WORK_TREE_ID.matcher(requireNonNull(id, "id"));
        if (matcher.matches()) {
            return Long.parseLong(matcher.group("localId"));
        }
        return null;
    }
}
