define('bitbucket/internal/feature/ssh/keys', [
    'aui',
    'jquery',
    'lodash',
    'bitbucket/util/navbuilder',
    'bitbucket/internal/feature/ssh/keys/access/common',
    'bitbucket/internal/feature/ssh/keys/access/delete-dialog',
    'bitbucket/internal/feature/ssh/keys/table',
    'bitbucket/internal/model/page-state',
    'bitbucket/internal/util/ajax',
    'bitbucket/internal/util/page-providers',
    'exports'
], function(
    AJS,
    $,
    _,
    nav,
    keyAccessCommon,
    keyAccessDeleteDialog,
    keysTable,
    pageState,
    ajax,
    pageProviders,
    exports
) {

    'use strict';

    var SshKeyTable = keysTable.SshKeyTable;
    var AjaxPageProvider = pageProviders.AjaxPageProvider;
    var CompositePageProvider = pageProviders.CompositePageProvider;
    var FilteredPageProvider = pageProviders.FilteredPageProvider;
    var OffsetPageProvider = pageProviders.OffsetPageProvider;
    var PreloadedPageProvider = pageProviders.PreloadedPageProvider;
    var filterPage = pageProviders.filterPage;
    var notEqKeyAccess = keyAccessCommon.notEqKeyAccess;

    // base builder for finding key acceses for a specific project/repo or keys for a user
    function restKeysBuilder() {
        if (pageState.getRepository()) {
            return nav.rest('keys').currentRepo().addPathComponents('ssh');
        }
        if (pageState.getProject()) {
            return nav.rest('keys').currentProject().addPathComponents('ssh');

        }
        return nav.rest('ssh').addPathComponents('keys');
    }

    // base builder for finding project/repo key access for a key and for deleting them
    function restKeysUsageBuilder() {
        return nav.rest('keys').addPathComponents('ssh');
    }

    function showWelcomeMat(welcomeMatTitleText, $table, addEnabled) {
        var $topAddKeyButton = $("#add-key-button");
        $topAddKeyButton.remove();
        var $paneDescription = $("#ssh-pane-description");
        $paneDescription.remove();
        var $noResultsRow = $(bitbucket.internal.widget.pagedTableMessage({
            content: bitbucket.internal.feature.ssh.keys.noResultsRow({
                // This is a little bit of a hack but it works and avoids
                // needing to figure out the url so don't judge me
                addKeyUrl: $topAddKeyButton.attr('href'),
                addEnabled: addEnabled,
                // This is getting a little messy
                welcomeMatTitleText: welcomeMatTitleText,
                noResultsContent: $paneDescription.html()
            })
        })).css('opacity', 0.0).insertAfter($table.addClass('no-results'));
        $noResultsRow.show();
        $noResultsRow.animate({'opacity': 1.0}, 500);
    }

    function spin($spinner, $button) {
        $spinner.insertAfter($button);
        $button.addClass('hidden');
        $spinner.spin('small');
    }

    function unspin($spinner) {
        $spinner.spinStop().remove();
    }

    function newDeletedKeyAlertOptions(isMultipleDelete) {
        return {
            title: AJS.I18n.getText('bitbucket.ssh.access.keys.delete.notfound'),
            message: isMultipleDelete ?
                AJS.I18n.getText('bitbucket.ssh.access.keys.delete.permission.multiplemessage') :
                AJS.I18n.getText('bitbucket.ssh.access.keys.delete.permission.single.message'),
            shouldReload: true,
            canClose: false,
            fallbackUrl: undefined
        };
    }

    function alreadyDeletedHandler(isMultipleDelete) {
        var showErrorDialog = function(xhr, textStatus, errorThrown, errors, dominantError) {
            return _.extend({}, dominantError, newDeletedKeyAlertOptions(isMultipleDelete));
        };

        return {
            statusCode: {
                '401' : showErrorDialog, //user has lost admin access to the project or repo containing the access key
                '404' : showErrorDialog  //project or repo no longer exists
            }
        };
    }

    var initialPageSize = 25;

    function getProjectAccess(key) {
        return ajax.rest(_.extend({
            url: restKeysUsageBuilder()
                .addPathComponents(key.id, 'projects')
                .withParams({
                    limit: initialPageSize,
                    avatarSize: bitbucket.internal.widget.avatarSizeInPx({ size: 'xsmall' })
                })
                .build(),
            type: 'GET'
        }, alreadyDeletedHandler()));
    }

    function getRepoAccesses(key) {
        return ajax.rest(_.extend({
            url: restKeysUsageBuilder()
                .addPathComponents(key.id, 'repos')
                .withParams({
                    limit: initialPageSize,
                    avatarSize: bitbucket.internal.widget.avatarSizeInPx({ size: 'xsmall' })
                })
                .build(),
            type: 'GET'
        }, alreadyDeletedHandler()));
    }

    function initTableForKeyAccesses($table, table, welcomeMatTitleText, addEnabled) {
        $table.on('click', '.delete-button', function (e) {
            e.preventDefault();
            var $button = $(this);
            var $tr = $button.closest('tr');
            var $spinner = $('<div class="spinner" />');
            var accessKey = { key: JSON.parse($tr.attr('data-key')), permission: $tr.attr('data-permission') };
            if (pageState.getRepository()) {
                accessKey = $.extend(accessKey, { repository: pageState.getRepository().toJSON() });
            } else {
                accessKey = $.extend(accessKey, { project: pageState.getProject().toJSON() });
            }
            var key = accessKey.key;

            var showWelcomeMatIfEmpty = function () {
                var $tBody = $tr.parent();
                $tr.remove();
                if ($tBody.children().size() === 0) {
                    showWelcomeMat(welcomeMatTitleText, $tBody.closest('table'), addEnabled);
                }
            };

            $.when(getProjectAccess(key), getRepoAccesses(key)).done(function(projectResponse, repoResponse) {
                var notCurrentKeyAccessFilter = _.partial(notEqKeyAccess, accessKey);
                var projAccessesPage1 = filterPage(projectResponse[0], notCurrentKeyAccessFilter);
                var repoAccessesPage1 = filterPage(repoResponse[0], notCurrentKeyAccessFilter);

                if (projAccessesPage1.size + repoAccessesPage1.size === 0) {

                    keyAccessDeleteDialog.showForSingleKeyAccess(accessKey, restKeysBuilder(),
                                                                 alreadyDeletedHandler(), showWelcomeMatIfEmpty);
                } else {
                    var avatarSizeParam = { avatarSize: bitbucket.internal.widget.avatarSizeInPx({ size: 'xsmall' }) };
                    var projAccessRestBuilder = restKeysUsageBuilder().addPathComponents(accessKey.key.id, 'projects').withParams(avatarSizeParam);
                    var projPageProvider = projAccessesPage1.isLastPage ?
                        new PreloadedPageProvider(projAccessesPage1.values) :
                        new CompositePageProvider([new PreloadedPageProvider(projAccessesPage1.values),
                                                   new OffsetPageProvider(new AjaxPageProvider(projAccessRestBuilder), projAccessesPage1.size)]);

                    var repoAccessRestBuilder = restKeysUsageBuilder().addPathComponents(accessKey.key.id, 'repos').withParams(avatarSizeParam);
                    var repoPageProvider = repoAccessesPage1.isLastPage ?
                        new PreloadedPageProvider(repoAccessesPage1.values) :
                        new CompositePageProvider([new PreloadedPageProvider(repoAccessesPage1.values),
                                                   new OffsetPageProvider(new AjaxPageProvider(repoAccessRestBuilder), repoAccessesPage1.size)]);

                    var pageProvider = new FilteredPageProvider(new CompositePageProvider([projPageProvider, repoPageProvider]), notCurrentKeyAccessFilter);

                    keyAccessDeleteDialog.showForMultipleKeyAccesses(accessKey, pageProvider, restKeysUsageBuilder(),
                                                                     alreadyDeletedHandler(true), showWelcomeMatIfEmpty);
                }
            });
        });

        table.init();
    }

    function initTableForUserKeys($table, table, welcomeMatTitleText, addEnabled, username) {
        $table.on('click', '.delete-button', function (e) {
            e.preventDefault();
            var $button = $(this);
            var $tr = $button.closest('tr');
            var keyId = $tr.attr('data-key-id');
            var builder = restKeysBuilder().addPathComponents(keyId);
            var $spinner = $('<div class="spinner" />');
            builder = builder.withParams({'user': username});

            spin($spinner, $button);

            ajax.rest({
                url: builder.build(),
                type: 'DELETE'
            }).done(function () {
                var $tBody = $tr.parent();
                $tr.remove();
                if ($tBody.children().size() === 0) {
                    showWelcomeMat(welcomeMatTitleText, $tBody.closest('table'), addEnabled);
                }
            }).always(function () {
                unspin($spinner);

                $button.removeClass('hidden');
            });
        });
        if (!$table.is(':visible')) {
            // if not presently visible the table is on a deselected user tab and so we should
            // resume and suspend as the tab is selected and deselected
            var hasInitialised = false;
            table.suspend();
            $("#page").on('tabSelect', '.tabs-menu a', function () {
                var $this = $(this);
                if ($this.attr('id') === 'ssh-tab') {
                    if (!hasInitialised) {
                        table.init();
                        hasInitialised = true;
                    }
                    table.resume();
                } else {
                    table.suspend();
                }
            });
        } else {
            table.init();
        }
    }

    exports.onReady = function(welcomeMatTitleText, addEnabled, username) {
        var table = new SshKeyTable(username, {
            target: "#ssh-keys-table",
            restKeysBuilder: restKeysBuilder
        });

        var $table = $("#ssh-keys-table");

        if (username) {
            initTableForUserKeys($table, table, welcomeMatTitleText, addEnabled, username);
        } else {
            initTableForKeyAccesses($table, table, welcomeMatTitleText, addEnabled);
        }
    };
});
