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

import com.atlassian.bitbucket.repository.MinimalRef;
import com.atlassian.bitbucket.repository.SimpleMinimalRef;
import com.atlassian.bitbucket.repository.StandardRefType;
import com.atlassian.bitbucket.scm.git.GitRefPattern;

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

import static com.atlassian.bitbucket.internal.mirroring.mirror.rest.cloud.RestCloudEntityProperties.*;

/**
 * Special handling of git ref changes from cloud since their refs in entities are never fully qualified and our
 * {@link MinimalRef MinimalRefs} need to provide this information. Note that changes to non-standard refs in cloud
 * will result in a web hook being fired but the changes list will be empty so ref qualification does not need to handle this.
 */
public class RestCloudExternalGitRefChange extends RestCloudExternalRefChange {

    public RestCloudExternalGitRefChange(Map<String, ?> values) {
        super(values);
    }

    @Nonnull
    @Override
    public MinimalRef getRef() {
        // the new or the old ref in the payload, depending on what type the change is
        Map<String, ?> refSubject = getRefSubject();
        // the type of the ref - branch or tag
        StandardRefType refType = getRefType(refSubject);

        // fq the id for Git. Cloud will *never* send us fq names and we will never get detailed changes
        // for non-standard refs (we will get a web hook notification with empty changes)
        String displayId = (String) refSubject.get(NAME);
        String id = displayId;
        switch (refType) {
            case BRANCH:
                id = GitRefPattern.HEADS.qualify(id);
                break;
            case TAG:
                id = GitRefPattern.TAGS.qualify(id);
                break;
            default:
                throw new IllegalStateException("Unknown ref type: " + refType);
        }

        return new SimpleMinimalRef.Builder()
                .type(refType)
                .id(id)
                .displayId(displayId)
                .build();
    }

    protected StandardRefType getRefType(Map<String, ?> refSubject) {
        StandardRefType refType;
        if (BRANCH.equals(refSubject.get(TYPE))) {
            refType = StandardRefType.BRANCH;
        } else if (TAG.equals(refSubject.get(TYPE))) {
            refType = StandardRefType.TAG;
        } else {
            throw new IllegalStateException("Unknown ref type: " + refSubject.get(TYPE));
        }
        return refType;
    }

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