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

import com.atlassian.bitbucket.internal.mirroring.mirror.ExternalRepository;
import com.atlassian.bitbucket.mirroring.mirror.UpstreamAccount;
import com.atlassian.bitbucket.rest.RestMapEntity;
import com.google.common.collect.Iterables;

import javax.annotation.Nonnull;
import java.util.Collections;
import java.util.Map;
import java.util.Optional;

import static com.atlassian.bitbucket.internal.mirroring.mirror.rest.server.RestServerEntityProperties.*;
import static java.util.Optional.empty;
import static java.util.Optional.ofNullable;

public class RestServerExternalRepository extends RestMapEntity implements ExternalRepository {

    @SuppressWarnings("OptionalUsedAsFieldOrParameterType")
    private Optional<String> cloneUrl;

    public RestServerExternalRepository() {
    }

    private RestServerExternalRepository(Map<String, Object> map) {
        super(map);
    }

    @Nonnull
    @Override
    public String getId() {
        return String.valueOf(get(ID));
    }

    @Nonnull
    @Override
    public String getName() {
        return getStringProperty(NAME);
    }

    @Nonnull
    @Override
    public Optional<ExternalRepository> getOrigin() {
        return ofNullable(valueOf(get(ORIGIN)));
    }

    @Nonnull
    @Override
    public Optional<UpstreamAccount> getOwner() {
        return empty();
    }

    @Nonnull
    @Override
    public RestServerExternalProject getProject() {
        return RestServerExternalProject.valueOf(get(PROJECT));
    }

    @Nonnull
    @Override
    public String getScmId() {
        return getStringProperty(SCM_ID);
    }

    @Nonnull
    @Override
    public String getSlug() {
        return getStringProperty(SLUG);
    }

    @SuppressWarnings("unchecked")
    @Nonnull
    @Override
    public Optional<String> getCloneUrl() {
        if (cloneUrl != null) {
            return cloneUrl;
        }

        // look up the links
        Object links = get("links");
        if (!(links instanceof Map<?, ?>)) {
            cloneUrl = empty();
            return cloneUrl;
        }

        Object cloneLinks = ((Map<String, ?>) links).get("clone");
        if (!(cloneLinks instanceof Iterable<?>)) {
            cloneUrl = empty();
            return cloneUrl;
        }

        Map<String, ?> sshLink = Iterables.find((Iterable<Map<String, ?>>) cloneLinks, map -> "ssh".equals(map.get("name")), null);
        if (sshLink != null) {
            cloneUrl = ofNullable((String) sshLink.get("href"));
            return cloneUrl;
        }

        cloneUrl = empty();
        return cloneUrl;
    }

    @Override
    public boolean isPublic() {
        return getBoolProperty(PUBLIC, false);
    }

    @Nonnull
    @Override
    public Optional<String> getContentHash() {
        return ofNullable((String) getProperties().get(CONTENT_HASH));
    }

    @SuppressWarnings("unchecked")
    private Map<String, Object> getProperties() {
        Object properties = get(PROPERTIES);
        if (properties instanceof Map<?, ?>) {
            return (Map<String, Object>) properties;
        }

        return Collections.emptyMap();
    }

    @SuppressWarnings("unchecked")
    public static RestServerExternalRepository valueOf(Object value) {
        if (value instanceof RestServerExternalRepository) {
            return (RestServerExternalRepository) value;
        }
        if (value instanceof Map<?, ?>) {
            return new RestServerExternalRepository((Map<String, Object>) value);
        }
        return null;
    }
}
