define('bitbucket/internal/page/branch/permissions', [
    'aui',
    'aui/flag',
    'jquery',
    'lodash',
    'bitbucket/util/navbuilder',
    'bitbucket/internal/feature/branch/permissions/dialog/branch-permissions-dialog',
    'bitbucket/internal/feature/branch/permissions/table/branch-permissions-table',
    'bitbucket/internal/model/branch/permissions/ref-matcher',
    'bitbucket/internal/model/branch/permissions/ref-restriction-collection',
    'bitbucket/internal/model/branch/permissions/supported-matcher-types',
    'bitbucket/internal/util/ajax',
    'bitbucket/internal/util/events',
    'bitbucket/internal/util/history',
    'exports'
], function (
    AJS,
    auiFlag,
    $,
    _,
    nav,
    BranchPermissionDialog,
    BranchPermissionTableView,
    RefMatcher,
    RefRestrictionCollection,
    SupportedMatcherTypes,
    ajax,
    events,
    history,
    exports
) {

    'use strict';

    function onReady(tableJSON, branch, isFirstContact) {
        var $content = $('#content');
        var $doc = $(document);
        var refRestrictions = new RefRestrictionCollection(tableJSON);

        var doEmptyCheck = function () {
            var $emptyStateBanner = $('#empty-state-banner');
            var $branchPermissionsTable = $('#branch-permissions-table');
            if (isFirstContact || refRestrictions.length > 0) {
                $emptyStateBanner.hide();
                $branchPermissionsTable.show();
            } else {
                $branchPermissionsTable.hide();
                $emptyStateBanner.show();
            }
        };
        doEmptyCheck();

        /**
         * When the dialog is closed bump off the 'at' query param from the URL to avoid the edit dialog
         * opening again when the user refreshes the page.
         */
        var resetUrl = function () {
            history.replaceState(null, null, nav.parse(window.location.href).deleteQueryParam('at'));
        };

        var dialogCallback = function (responseArray, operation) {
            responseArray.forEach(function (response) {
                if (response) {
                    switch (response.type) {
                        case 'DELETE':
                            refRestrictions.remove(response.id);
                            break;
                        case 'PUT':
                            refRestrictions.add(response.refRestriction);
                            break;
                        default:
                            refRestrictions.add(response);
                    }
                }
            });
            var stringToShow;
            switch (operation) {
                case 'CREATE':
                    stringToShow = AJS.I18n.getText('bitbucket.web.branch.permissions.notification.created.success');
                    break;
                case 'UPDATE':
                    stringToShow = AJS.I18n.getText('bitbucket.web.branch.permissions.notification.updated.success');
                    break;
                case 'DELETE':
                    stringToShow = AJS.I18n.getText('bitbucket.web.branch.permissions.notification.removed.success');
                    break;
                default:
                    throw new Error('Unsupported operation type: ' + operation);
            }
            doEmptyCheck();
            populateBranchModelBranches();
            auiFlag({
                type: 'success',
                title: stringToShow,
                persistent: false,
                close: 'auto',
                body: ''
            });
        };
        var view = new BranchPermissionTableView({el: $('.branch-permissions-table'), refRestrictions: refRestrictions});

        if (branch) {
            var permissions = [];
            refRestrictions.each(function (refRestriction) {
                var matcher = refRestriction.getMatcher();
                if (matcher.getId() === branch.id && matcher.getType().getId() === SupportedMatcherTypes.BRANCH) {
                    permissions.push(refRestriction);
                }
            });
            var dialog = new BranchPermissionDialog(
                refRestrictions, BranchPermissionDialog.getDialogOptionsFor(new RefMatcher().branch(branch), permissions));
            dialog._dialog.on('hide', resetUrl);
            dialog.show(dialogCallback);
        }

        var populateBranchModelBranches = function () {
            var $categoryRestrictions = $('tbody[data-branch-type="' + SupportedMatcherTypes.MODEL_CATEGORY + '"]');
            var $branchRestrictions = $('tbody[data-branch-type="' + SupportedMatcherTypes.MODEL_BRANCH + '"]');

            if ($categoryRestrictions === null && $branchRestrictions === null) {
                return;
            }

            ajax.rest({
                url: nav.rest('branch-utils', 'latest').currentRepo().addPathComponents('branchmodel').build(),
                statusCode: {
                    '*': false
                }
            }).then(function (response) {
                var branchModelLink = nav.pluginServlets()
                    .path('branchmodel')
                    .currentRepo()
                    .build();

                function maybeReplaceBranchName($el, name) {
                    var $branchNameText = $el.find('.branch-name-text');
                    if (!$branchNameText.parent().hasClass('branch-name')){
                        $branchNameText.replaceWith(bitbucket.internal.page.branchPermissions.branchName({
                            branchName: name,
                            isABranch: true
                        }));
                    }
                }

                function updateBranchingModelBranch(type, displayId, descriptionHTML) {
                    var $el = $('[data-branch-value="' + type + '"]');
                    maybeReplaceBranchName($el, displayId);
                    $el.find('.branch-model-branch').html(descriptionHTML);
                }

                if (response.development) {
                    updateBranchingModelBranch('development',
                        response.development.displayId,
                        AJS.I18n.getText('bitbucket.web.branch.permissions.table.cell.model.branch.development.description.html', branchModelLink)
                    );
                }

                if (response.production) {
                    updateBranchingModelBranch('production',
                        response.production.displayId,
                        AJS.I18n.getText('bitbucket.web.branch.permissions.table.cell.model.branch.production.description.html', branchModelLink)
                    );
                }

                if (response.types) {
                    response.types.forEach(function (type) {
                        var $type = $('[data-branch-value="' + type.id + '"]');
                        $type.find('.branch-name-text').text(type.prefix);
                        $type.find('.branch-model-category').html(
                            AJS.I18n.getText('bitbucket.web.branch.permissions.table.cell.model.category.specific.description.html',
                                AJS.escapeHtml(type.displayName), branchModelLink));
                    });
                }
            });
        };
        populateBranchModelBranches();

        $content.on('click', '#view-permissions-button', function (e) {
            e.preventDefault();
            isFirstContact = false;
            view.reRender($('#branch-permissions-content'));
            doEmptyCheck();
        });

        $content.on('click', '#add-permission-button, #add-permission-button-empty-state', function (e) {
            e.preventDefault();
            new BranchPermissionDialog(refRestrictions).show(dialogCallback);
        });

        $content.on('click', '.branch-permissions-table .delete-button', function (e) {
            e.preventDefault();
            var $row = $(this).closest('tbody');
            $row.addClass('active');
            var branchName = $row.find('.branch-name-cell .branch-name-text').text();
            $('#branch-permissions-content').append(aui.dialog.dialog2({
                content: AJS.I18n.getText('bitbucket.web.branch.permissions.table.actions.delete.confirm.content', AJS.escapeHtml(branchName)),
                modal: true,
                removeOnHide: true,
                id: 'branch-permission-delete-confirm-dialog',
                size: 'small',
                titleText: AJS.I18n.getText('bitbucket.web.branch.permissions.table.actions.delete.confirm.header'),
                extraClasses: 'aui-dialog2-warning',
                footerActionContent: bitbucket.internal.page.branchPermissions.confirmCancelButtons()
            }));
            AJS.dialog2('#branch-permission-delete-confirm-dialog').show();
        });

        $doc.on('aui-layer-hide', function (e) {
            $('tbody').removeClass('active');
        });

        $doc.on('click', '.delete-cancel-button', function (e) {
            AJS.dialog2('#branch-permission-delete-confirm-dialog').hide();
        });

        $doc.on('click', '.delete-confirm-button', function (e) {
            e.preventDefault();

            var $row = $('tbody.active');
            AJS.dialog2('#branch-permission-delete-confirm-dialog').hide();

            BranchPermissionTableView.showRowSpinner($row);
            BranchPermissionTableView.hideDeleteButton($row);

            var permissionDeletes = [];
            var permissionIds = [];
            var $permissionRows = $row.find('tr[data-id]');
            $permissionRows.each(function (i, element) {
                var id = $(element).data('id');
                permissionIds.push(id);
                var permission = refRestrictions.get(id);
                if (permission) {
                    permissionDeletes.push(permission.remove());
                }
            });

            if (!permissionDeletes.length) {
                BranchPermissionTableView.hideRowSpinner($row);
                BranchPermissionTableView.showDeleteButton($row);
                auiFlag({
                    type: 'error',
                    title: AJS.I18n.getText('bitbucket.web.branch.permissions.notification.removed.failure'),
                    persistent: false,
                    close: 'auto',
                    body: ''
                });
                return;
            }

            $.when.apply($, permissionDeletes)
                .always(function () {
                    BranchPermissionTableView.hideRowSpinner($row);
                    BranchPermissionTableView.showDeleteButton($row);
                }).done(function () {
                    permissionIds.forEach(function (id) {
                        refRestrictions.remove(id);
                    });
                    doEmptyCheck();
                    auiFlag({
                        type: 'success',
                        title: AJS.I18n.getText('bitbucket.web.branch.permissions.notification.removed.success'),
                        persistent: false,
                        close: 'auto',
                        body: ''
                    });
                }).fail(function () {
                    auiFlag({
                        type: 'error',
                        title: AJS.I18n.getText('bitbucket.web.branch.permissions.notification.removed.failure'),
                        persistent: false,
                        close: 'auto',
                        body: ''
                    });
                });
        });

        $content.on('click', '.branch-permissions-table .edit-button', function (e) {
            e.preventDefault();

            var $row = $(this).closest('tbody');

            var rowMatcher = new RefMatcher({
                id : $row.data('branch-value'),
                type : { id : $row.data('branch-type') }
            });

            var permissions = refRestrictions.filter(function (refRestriction) {
                return refRestriction.getMatcher().equals(rowMatcher);
            });

            if (!permissions.length) {
                auiFlag({
                    type: 'error',
                    title: AJS.I18n.getText('bitbucket.web.branch.permissions.notification.updated.failure'),
                    persistent: false,
                    close: 'auto',
                    body: ''
                });
                return;
            }

            new BranchPermissionDialog(
                refRestrictions, BranchPermissionDialog.getDialogOptionsFor(permissions[0].getMatcher(), permissions, null)).show(dialogCallback);
        });
    }

    exports.onReady = function (tableJSON, branch, isFirstContact) {
        var callback = _.once(onReady).bind(null, tableJSON, branch, isFirstContact);
        events.on('bitbucket.internal.model.page-state.changed.project', callback);
        $(document).ready(callback);
    };

});
