define('feature/mirroring/clone-url', [
    'aui',
    'jquery',
    'lodash',
    'bitbucket/util/navbuilder',
    'bitbucket/util/state',
    'bitbucket/internal/bbui/mirror-clone-selector/mirror-clone-selector',
    'bitbucket/internal/util/ajax',
    'bitbucket/internal/util/browser-window',
    'bitbucket/internal/util/events'
], function(
    AJS,
    $,
    _,
    nav,
    state,
    MirrorSelector,
    ajax,
    window,
    events
) {
    'use strict';

    var mirrorSelector;
    var knownProtocolsByWebItemKey = {
        'http-clone-url': 'http',
        'ssh-clone-url-default': 'ssh',
        'ssh-clone-url-alternate': 'ssh'
    };

    /**
     * @typedef {Object} MirrorRepositoryDescriptor
     * @param {MirrorServer} mirrorServer
     */

    /**
     * @typedef {Object} MirrorServer
     * @param {string} id
     * @param {string} name
     * @param {string} baseUrl
     */

    /**
     * @typedef {Object} MinimalMirrorServer
     * @param {string} id
     * @param {string} name
     * @param {string} baseUrl
     * @param {string} url
     */

    function repo() {
        return state.getRepository();
    }

    function repoId() {
        return repo().id;
    }

    function projectId() {
        return state.getProject().id;
    }

    /**
     * Maps an array of mirrors to the correct representation the CloneSelector expects.
     *
     * @param {Array<MirrorRepositoryDescriptor>} mirrorDescriptors
     * @return {Array<MinimalMirrorServer>}
     */
    function minimalMirrors(mirrorDescriptors) {
        return _.compact(_.map(mirrorDescriptors, function (descriptor) {
            var authorizedLink = _.get(descriptor, 'links.self[0].href');
            if (authorizedLink) {
                var mirror = descriptor.mirrorServer;
                return {
                    id: mirror.id,
                    name: mirror.name,
                    baseUrl: mirror.baseUrl,
                    url: authorizedLink
                }
            } else {
                return false;
            }
        }));
    }

    function getPrimary() {
        return {
            mirrorName: AJS.I18n.getText('bitbucket.mirroring.clone.primary'),
            links: repo().links
        };
    }

    function updateCloneProtocol(webItemKey) {
        if (!mirrorSelector) {
            return;
        }

        var protocol = knownProtocolsByWebItemKey[webItemKey];
        if (protocol) {
            mirrorSelector.updateCloneProtocol(protocol);
            mirrorSelector.show();
        } else {
            mirrorSelector.hide();
        }
    }

    function getCloneProtocol() {
        return $('.clone-url .repository-protocol').text().toLowerCase();
    }

    function getMirrors() {
        return ajax.rest({
            url: nav.rest('mirroring')
                .addPathComponents('repos', repoId(), 'mirrors')
                .build(),
            statusCode: {
                '*': false
            }
        }).then(function (data) {
            return minimalMirrors(data.values || []);
        }).done(function () {
            events.on('bitbucket.internal.clone.dialog.hidden', mirrorSelector.hideDropdown);
        });
    }

    function updatePreferredMirror(mirrorId) {
        events.trigger('bitbucket.internal.ui.mirroring.mirror.updated', null, {
            repositoryId: repoId(),
            projectId: projectId()
        });

        ajax.rest({
            url: nav.rest('mirroring')
                .addPathComponents('account', 'settings', 'preferred-mirror')
                .build(),
            type: mirrorId ? 'POST' : 'DELETE',
            statusCode: {
                '*': false
            },
            data: mirrorId
        });
    }

    function updateCloneUrl(protocol, cloneUrl) {
        var $input = $('.clone-url .clone-url-input');
        $input.val(cloneUrl).select();

        events.trigger('bitbucket.internal.feature.repository.clone.mirror.changed', null, protocol, cloneUrl);
    }

    function initHandler() {
        //We initialise the cloneSelector here to ensure that it is only created when the user is about
        //to open the clone dialog.
        if (!mirrorSelector) {
            mirrorSelector = new MirrorSelector(document.getElementById('mirroring-clone-url-container'), {
                cloneProtocol: getCloneProtocol(),
                getMirrors: getMirrors,
                preferredMirrorId: window.WRM.data.claim('com.atlassian.bitbucket.server.bitbucket-mirroring-upstream:preferred-mirror.preferred-mirror-id'),
                primary: getPrimary(),
                updateCloneUrl: updateCloneUrl,
                updatePreferredMirror: updatePreferredMirror
            });
            mirrorSelector.load();
        }
    }

    function detachEventHandlers() {
        events.off('bitbucket.internal.feature.repository.clone.protocol.initial', updateCloneProtocol);
        events.off('bitbucket.internal.feature.repository.clone.protocol.changed', updateCloneProtocol);
        $(window.document).off('mouseenter focus click', '#clone-repo-button', initHandler);
    }

    function attachEventHandlers() {
        events.on('bitbucket.internal.feature.repository.clone.protocol.initial', updateCloneProtocol);
        events.on('bitbucket.internal.feature.repository.clone.protocol.changed', updateCloneProtocol);

        /*
         * Initializes the fragment with the content provided by the server.
         *
         * Note: This code sits behind a IsDataCenterLicenseCondition and IsMirrorAttachedCondition.
         *
         * Initialisation of the component only happens when we see "intent to clone", as the REST call can only be
         * cached on a per-repository basis and is potentially expensive.
         */
        $(window.document).on('mouseenter focus click', '#clone-repo-button', initHandler);
    }

    return {
        /*
         * This call may occur before the clone dialog is rendered. We are careful to *only* register global events
         * that trigger the actual initialisation lazily.
         */
        onReady: attachEventHandlers,
        cleanup: function() {
            detachEventHandlers();
            mirrorSelector = undefined;
        }
    };
});