define('bitbucket/internal/build/status/dialog', [
    'aui',
    'jquery',
    'bitbucket/internal/util/ajax',
    'bitbucket/internal/util/dom-event'
], function (
    AJS,
    $,
    ajax,
    domEventUtil
) {

    var dialogId = 'build-status-dialog';
    var dialogPanelClass = 'build-status-dialog-panel';

    function BuildStatusDialog() {
        this._instance = null;
        this._xhr = null;
    }

    BuildStatusDialog.prototype.bindTo = function(parent, triggerSelector, event, getCommitId) {
        var self = this;
        $(parent).on(event, triggerSelector, function (e) {
            const href = $(this).prop('href');
            const hasHref = href && href !== location.href + '#' && href !== location.href;
            if (!domEventUtil.openInSameTab(e) && hasHref) {
                // multiple builds can't be opened in a new tab (we have no page to go to)
                // make sure that we've actually set the href too. PR Overview uses a link with a hash which is useless.
                return;
            }

            e.preventDefault();
            self.showFor(getCommitId($(this)));
        });
    };

    BuildStatusDialog.prototype.showFor = function(commitId) {
        if (this._instance) {
            this._instance.remove();
        }

        var $spinner = $('<div class="spinner"></div>');
        this._instance = createDialog(this, $spinner);
        this._instance.show();
        $('.button-panel-link').focus();
        $spinner.show().spin('large');

        fetchResults(this, commitId).always(function() {
            $spinner.spinStop().remove();
        });
    };

    // --- internal methods ---

    function cancelDialog(self) {
        if (self._instance) {
            // the event handler for 'hideLayer' will automatically remove the dialog from the DOM
            self._instance.hide();
        }
    }

    function cancelRequest(self) {
        if (self._xhr) {
            // the 'always()' handler for the XHR request will set this to null
            self._xhr.abort();
        }
    }

    function createDialog(self, $content) {
        var dialog = new AJS.Dialog({
            closeOnOutsideClick: true,
            id: dialogId,
            height: 240,
            width: 600,
            keypressListener: function (e) {
                if (e.keyCode === AJS.keyCode.ESCAPE) {
                    cancelDialog(self);
                }
            }
        }).addHeader(AJS.I18n.getText('bitbucket.build.status.dialog.title'))
          .addPanel('', $content, dialogPanelClass)
          .addLink(AJS.I18n.getText('bitbucket.web.button.close'), function() {
              cancelDialog(self);
          });

        // remove the dialog when it is hidden (which happens if the user clicks outside the dialog,
        // clicks on the 'Close' button or presses the escape key)
        $(document).one('hideLayer', function() {
            removeDialog(self);
        });

        return dialog;
    }

    function fetchResults(self, commitId) {
        self._xhr = ajax.rest({
            url: getUrl(commitId)
        }).fail(function () {
            // cancel the dialog, since the default error handling from ajax.rest() will
            // also show an error dialog (or redirect to the login page);
            // this avoids having the error dialog showing up on top of the build status dialog.
            cancelDialog(self);
        }).done(function (page) {
            updateDialog(self, bitbucket.internal.build.status.dialogList({ statuses: page.values}));
        }).always(function() {
            self._xhr = null;
        });
        return self._xhr;
    }

    function getUrl(commitId) {
        return AJS.contextPath() + '/rest/build-status/latest/commits/' + encodeURIComponent(commitId);
    }

    function removeDialog(self) {
        // cancel any in-flight request first
        cancelRequest(self);

        if (self._instance) {
            self._instance.remove();
            self._instance = null;
        }
    }

    function updateDialog(self, content) {
        self._instance.getCurrentPanel().html(content);
        self._instance.updateHeight();
    }

    return BuildStatusDialog;

});
