define('branch/automerge-decorator', [
    'aui',
    'jquery',
    'lodash',
    'bitbucket/util/navbuilder',
    'bitbucket/internal/util/ajax',
    'exports'
], function (
    AJS,
    $,
    _,
    nav,
    ajax,
    exports
) {

    /**
     * constructs a URL using navBuilder for the branch auto-merge path REST resource
     * @param {Repository} repo     the target repository for auto-merge
     * @param {string} branchRefId  the ref ID of the target branch
     * @returns (string)            the REST URL for auto-merging
     */
    function getRestAutomergePathUrl(repo, branchRefId) {
        return nav.rest('branch-utils').project(repo.getProject()).repo(repo)
            .addPathComponents('automerge', 'path')
            .withParams({'branchRefId': branchRefId})
            .build();
    }

    /**
     * makes the ajax request to get the auto-merge path
     * @param {RevisionReference} toRef  the target revision reference (eg branch)
     * @returns {xhr}                    the ajax response
     */
    function requestAutoMerge(toRef) {
        return ajax.rest({
            url : getRestAutomergePathUrl(toRef.getRepository(), toRef.getId())
        });
    }

    /**
     * replaces the default merge diagram in the merge dialog if there's an automerge path, otherwise show the original
     * merge diagram again
     *
     * @param {PullRequest} pullRequest  the current pull request
     * @param {jQuery} $originalDiagram  the branch diagram element that will get replaced if automerge is available
     * @param {jQuery} $spinner          the spinner element
     */
    function replaceMergeDiagram(pullRequest, $originalDiagram, $spinner) {
        var fromRef = pullRequest.getFromRef();
        var toRef = pullRequest.getToRef();
        var $currentDiagram = $originalDiagram.addClass('pending');

        requestAutoMerge(toRef).done(function(data) {
            if (data.status.available) {
                var mergePath = data.path.slice(1); // remove target ref from response since we already have it
                $currentDiagram = $(bitbucket.internal.feature.automerge.diagram({
                    'sourceRef': fromRef.toJSON(),
                    'targetRef': toRef.toJSON(),
                    'mergePath': mergePath
                }));
                $spinner.replaceWith($currentDiagram);

                var $automergePath = $currentDiagram.find('.automerge-path');

                // only show the "Show More" button if there's more than 2 additional branches
                if (mergePath.length > 2) {
                    $automergePath.addClass('collapsed').after(
                        bitbucket.internal.feature.automerge.expandCascadeButton({
                            'mergePathRefCount': mergePath.length - 1 // we are already showing at least one additional ref, so deduct the count by 1
                        }));
                    $('#expand-automerge-path-button').on('click', function() {
                        $(this).remove();
                        $automergePath.removeClass('collapsed');
                    });
                }

            } else {
                $spinner.replaceWith($currentDiagram.addClass('pending'));

                if (data.status.id === 'PATH_TOO_LONG') {
                    $currentDiagram.after(
                        aui.message.warning({
                            'content': AJS.I18n.getText('bitbucket.branchmodel.automerge.warning.path.too.long')
                        })
                    );
                }
            }
            $spinner = null;
        }).fail(function(xhr, textStatus, error, errorJson) {
            $spinner.spinStop();
        }).always(function() {
            _.defer(function() { // transition won't start without the defer.
                $currentDiagram.removeClass('pending');
            });
        });
    }

    /**
     * replaces the merge diagram with a spinner and makes a request to see if it needs to be replaced with the
     * automerge diagram showing the merge path
     *
     * @param {jQuery} $originalDiagram  the merge diagram element
     * @param {PullRequest} pullRequest  the current pull request
     */
    function decorateDiagram($originalDiagram, pullRequest) {
        if ($originalDiagram.length) {
            var $spinner = $('<div class="branch-diagram-spinner"></div>');
            var $parentDialog = $originalDiagram.closest('.aui-layer');

            $originalDiagram.replaceWith($spinner);
            var beginRequestOnce = _.once(function() {
                if ($spinner) {
                    $spinner.spin('large');
                }
                replaceMergeDiagram(pullRequest, $originalDiagram, $spinner);
            });

            if ($parentDialog.is(':visible')) {
                beginRequestOnce();
            } else {
                AJS.layer($parentDialog).on('show', beginRequestOnce);
            }
        }
    }

    exports.decorateDiagram = decorateDiagram;
});
