package com.atlassian.stash.internal.rest.renderer;

import com.atlassian.bitbucket.nav.NavBuilder;
import com.atlassian.bitbucket.rest.RestEntityOutOfDateErrorMessage;
import com.atlassian.bitbucket.rest.RestErrorMessage;
import com.atlassian.bitbucket.rest.RestRequestCanceledMessage;
import com.atlassian.bitbucket.rest.auth.RestAuthenticationRequiredErrorMessage;
import com.atlassian.bitbucket.rest.cluster.RestClusterInformation;
import com.atlassian.bitbucket.rest.cluster.RestClusterNode;
import com.atlassian.bitbucket.rest.comment.RestComment;
import com.atlassian.bitbucket.rest.comment.RestDiffCommentAnchor;
import com.atlassian.bitbucket.rest.commit.RestChangeset;
import com.atlassian.bitbucket.rest.commit.RestCommit;
import com.atlassian.bitbucket.rest.commit.RestCommitDiscussionParticipant;
import com.atlassian.bitbucket.rest.commit.RestMinimalCommit;
import com.atlassian.bitbucket.rest.content.*;
import com.atlassian.bitbucket.rest.hook.repository.RestRepositoryHook;
import com.atlassian.bitbucket.rest.license.RestBitbucketLicense;
import com.atlassian.bitbucket.rest.project.RestPersonalProject;
import com.atlassian.bitbucket.rest.project.RestProject;
import com.atlassian.bitbucket.rest.property.RestPropertyMap;
import com.atlassian.bitbucket.rest.pull.*;
import com.atlassian.bitbucket.rest.repository.*;
import com.atlassian.bitbucket.rest.scm.RestMergeErrorMessage;
import com.atlassian.bitbucket.rest.task.RestTask;
import com.atlassian.bitbucket.rest.task.RestTaskOperations;
import com.atlassian.bitbucket.rest.user.*;
import com.atlassian.bitbucket.rest.util.RestJsonable;
import com.atlassian.json.marshal.JsonableMarshaller;
import org.springframework.util.ClassUtils;

import java.lang.reflect.Constructor;

public class CommonRestAggregateBuilder extends AggregateBuilder {

    private final JsonableMarshaller jsonableMarshaller;

    public CommonRestAggregateBuilder(NavBuilder navBuilder, JsonableMarshaller jsonableMarshaller) {
        super(navBuilder);
        this.jsonableMarshaller = jsonableMarshaller;

        registerSurrogate(RestAuthenticationRequiredErrorMessage.class);
        registerSurrogate(RestBlame.class);
        registerSurrogate(RestBranch.class);
        registerSurrogate(RestCaptchaAuthenticationException.class);
        registerSurrogate(RestChange.class);
        registerSurrogate(RestChangeset.class);
        registerSurrogate(RestClusterInformation.class);
        registerSurrogate(RestClusterNode.class);
        registerSurrogate(RestComment.class);
        registerSurrogate(RestCommit.class);
        registerSurrogate(RestConflict.class);
        registerSurrogate(RestConflictChange.class);
        registerSurrogate(RestConflictingRefNameMessage.class);
        registerSurrogate(RestCommitDiscussionParticipant.class);
        registerSurrogate(RestDetailedGroup.class);
        registerSurrogate(RestDetailedUser.class);
        registerSurrogate(RestDiff.class);
        registerSurrogate(RestDiffCommentAnchor.class);
        registerSurrogate(RestDiffHunk.class);
        registerSurrogate(RestDiffLine.class);
        registerSurrogate(RestDiffSegment.class);
        registerSurrogate(RestDirectory.class);
        registerSurrogate(RestDuplicatePullRequestErrorMessage.class);
        registerSurrogate(RestDuplicateRefMessage.class);
        registerSurrogate(RestEntityOutOfDateErrorMessage.class);
        registerSurrogate(RestErrorMessage.class);
        registerSurrogate(RestFile.class);
        registerSurrogate(RestInvalidPullRequestReviewersErrorMessage.class);
        registerSurrogate(RestInvalidRefNameMessage.class);
        registerSurrogate(RestJsonable.class);
        registerSurrogate(RestMergeErrorMessage.class);
        registerSurrogate(RestPullRequestMergeVeto.class);
        registerSurrogate(RestMetadataMap.class);
        registerSurrogate(RestMinimalCommit.class);
        registerSurrogate(RestMinimalRef.class);
        registerSurrogate(RestPath.class);
        registerSurrogate(RestPermittedGroup.class);
        registerSurrogate(RestPermittedUser.class);
        registerSurrogate(RestPermittedUser.class);
        registerSurrogate(RestPerson.class);
        registerSurrogate(RestPersonalProject.class);
        registerSurrogate(RestProject.class);
        registerSurrogate(RestPropertyMap.class);
        registerSurrogate(RestPullRequest.class);
        registerSurrogate(RestPullRequestActivity.class);
        registerSurrogate(RestPullRequestActivityPage.class);
        registerSurrogate(RestPullRequestCommentActivity.class);
        registerSurrogate(RestPullRequestDiffCommentAnchor.class);
        registerSurrogate(RestPullRequestMergeActivity.class);
        registerSurrogate(RestPullRequestMergeConfig.class);
        registerSurrogate(RestPullRequestMergeStrategy.class);
        registerSurrogate(RestPullRequestMergeVetoedErrorMessage.class);
        registerSurrogate(RestPullRequestMergeability.class);
        registerSurrogate(RestPullRequestOutOfDateErrorMessage.class);
        registerSurrogate(RestPullRequestParticipant.class);
        registerSurrogate(RestPullRequestRef.class);
        registerSurrogate(RestPullRequestRescopeActivity.class);
        registerSurrogate(RestPullRequestReviewersUpdatedActivity.class);
        registerSurrogate(RestRef.class);
        registerSurrogate(RestRefChange.class);
        registerSurrogate(RestSubmodule.class);
        registerSurrogate(RestRepository.class);
        registerSurrogate(RestRepositoryHook.class);
        registerSurrogate(RestRequestCanceledMessage.class);
        registerSurrogate(RestRescopeDetails.class);
        registerSurrogate(RestRequestCanceledMessage.class);
        registerSurrogate(RestBitbucketLicense.class);
        registerSurrogate(RestApplicationUser.class);
        registerSurrogate(RestTag.class);
        registerSurrogate(RestTask.class);
        registerSurrogate(RestTaskOperations.class);
    }

    @Override
    protected SurrogateBuilder createSurrogate(Class<?> surrogateClass, Class<?> targetClass) {
        // The JsonableMarshaller constructor is required by RestMetadataMap
        Constructor<?> ctor = ClassUtils.getConstructorIfAvailable(surrogateClass, new Class[]{targetClass, JsonableMarshaller.class});
        if (ctor != null) {
            return new DefaultSurrogateBuilder(ctor, jsonableMarshaller);
        }

        return super.createSurrogate(surrogateClass, targetClass);
    }
}
