package com.atlassian.bitbucket.internal.mirroring.mirror.rest;

import com.atlassian.bitbucket.mirroring.mirror.MirroredRepository;
import com.atlassian.bitbucket.mirroring.mirror.MirroredRepositoryStatus;
import com.atlassian.bitbucket.rest.RestMapEntity;
import com.atlassian.bitbucket.rest.annotation.JsonSurrogate;
import com.atlassian.bitbucket.rest.util.RestNamedLink;
import com.atlassian.bitbucket.util.NamedLink;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import org.codehaus.jackson.map.annotate.JsonSerialize;

import javax.annotation.Nonnull;
import java.util.Date;
import java.util.Optional;
import java.util.Set;

import static java.util.Objects.requireNonNull;
import static java.util.stream.Collectors.toSet;

@JsonSerialize
@JsonSurrogate(MirroredRepository.class)
public class RestMirroredRepository extends RestMapEntity implements MirroredRepository {

    public static final String AVAILABLE = "available";
    public static final String LINKS = "links";
    public static final String MIRROR_NAME = "mirrorName";
    public static final String UPDATED_DATE = "updatedDate";
    public static final String REPOSITORY_ID = "repositoryId";
    public static final String STATUS = "status";

    private RestMirroredRepository(String mirrorName, String upstreamRepoId, Set<RestNamedLink> cloneUrls,
                                   MirroredRepositoryStatus status, Optional<Date> updatedDate) {
        put(AVAILABLE, status == MirroredRepositoryStatus.AVAILABLE || status == MirroredRepositoryStatus.ERROR_AVAILABLE);
        put(LINKS, ImmutableMap.of("clone", cloneUrls));
        put(MIRROR_NAME, mirrorName);
        put(REPOSITORY_ID, upstreamRepoId);
        put(STATUS, status);
        putIfNotNull(UPDATED_DATE, updatedDate.orElse(null));
    }

    public RestMirroredRepository(@Nonnull MirroredRepository info) {
        this(requireNonNull(info, "mirroredRepository").getMirrorName(), info.getRepositoryId(), info.getCloneUrls()
                .stream().map(RestNamedLink::new).collect(toSet()), info.getStatus(), info.getLastUpdated());
    }

    @Nonnull
    @Override
    public Set<NamedLink> getCloneUrls() {
        return (Set<NamedLink>) get(LINKS);
    }

    @Nonnull
    @Override
    public String getMirrorName() {
        return getStringProperty(MIRROR_NAME);
    }

    @Nonnull
    @Override
    public Optional<Date> getLastUpdated() {
        Date updatedDate = (Date) get(UPDATED_DATE);
        return updatedDate != null ?  Optional.of(updatedDate) : Optional.<Date>empty();
    }

    @Nonnull
    @Override
    public String getRepositoryId() {
        return getStringProperty(REPOSITORY_ID);
    }

    @Nonnull
    @Override
    public MirroredRepositoryStatus getStatus() {
        return getEnumProperty(STATUS, MirroredRepositoryStatus.class);
    }

    @Override
    public boolean isAvailable() {
        return getBoolProperty(AVAILABLE);
    }

    public static final RestNamedLink EXAMPLE_MIRROR_URL_HTTP = new RestNamedLink("https://admin@saigon.stash.example.com/scm/awesomeproject/awesomerepo.git", "http");

    public static final RestNamedLink EXAMPLE_MIRROR_URL_SSH = new RestNamedLink("ssh://git@saigon.stash.example.com:7999/awesomeproject/awesomerepo.git", "ssh");

    public static final RestMirroredRepository EXAMPLE = new RestMirroredRepository("Saigon Mirror", "1", ImmutableSet.of(EXAMPLE_MIRROR_URL_HTTP, EXAMPLE_MIRROR_URL_SSH), MirroredRepositoryStatus.AVAILABLE, Optional.of(new Date()));
}
