require.config({
  paths: {
    'xwiki-suggestUsers': "../../resources/uicomponents/suggest/suggestUsersAndGroups.min.js"
  }
});
require(['deferred!ckeditor', 'xwiki-suggestUsers', 'jquery', 'xwiki-meta'], function (ckeditorPromise, suggestUsers, $, xm) {

  /**
   * Get the current wiki scope for displaying global, local or global and local users
   */
  const userScope = "LOCAL_AND_GLOBAL";

  // see https://stackoverflow.com/a/6248722/657524
  function random6chars() {
    // I generate the UID from two parts here 
    // to ensure the random number provide enough bits.
    var firstPart = (Math.random() * 46656) | 0;
    var secondPart = (Math.random() * 46656) | 0;
    firstPart = ("000" + firstPart.toString(36)).slice(-3);
    secondPart = ("000" + secondPart.toString(36)).slice(-3);
    return firstPart + secondPart;
  }

  /**
   * Compute a new unique anchor for the given reference.
   * The unique anchor is based on the mentionned user id, concatenaed with a random string of 6 alphanumeric
   * characters.
   * The chances of collision are quite low, about 46k mentions for a given mentioned user on a given page (assuming
   * that no mentions are ever deleted).
   */
  const getAnchor = function (reference) {
    const refId = reference.replace(/[.:]/g, '-');
    const randomId = random6chars();
    return refId + '-' + randomId;
  };

  const search = function (text, callback) {
    const params = {
      'input': text,
      'limit': 6,
    };
    suggestUsers.loadUsers(userScope, params).then(users => {
      const cct = users.map(function (x) {
        // insert an id because that's required by the mentions plugins.
        x.id = x.value;
        // Make sure to display the icon avatar or the image one.
        if (x.icon.cssClass) {
          x.imgClass = "hidden";
          x.cssClass = x.icon.cssClass;
        } else {
          x.imgUrl = x.icon.url;
          x.cssClass = "hidden";
          x.imgClass = "";
        }
        x.iconHtml
        return x;
      });
      callback(cct);
    });
  }

  ckeditorPromise.then(ckeditor => {
    function getUserMentionsConfig(editor) {
      return {
        feed: function (opts, callback) {
          search(opts.query, callback);
        },
        marker: '@',
        minChars: 0,
        itemsLimit: 6,
        itemTemplate:
         `<li data-id="{id}" class="ckeditor-autocomplete-item">
            <div>
              <span class="ckeditor-autocomplete-item-icon-wrapper">
                <span class="{cssClass}"></span>
                <img src="{imgUrl}" class="{imgClass}"/>
              </span>
              <span class="ckeditor-autocomplete-item-label">{label}</span>
            </div>
          </li>`,
        outputTemplate: function (param) {
          editor.once('afterInsertHtml', function() {
            editor.execCommand('xwiki-macro-insert', {
              name: 'mention',
              inline: 'enforce',
              parameters: {
                reference: param.id,
                style: 'FULL_NAME',
                anchor: getAnchor(param.id)
              }
            });
          });
          // the outputTemplate insert nothing but wait for the afterInsertHtml event to be triggered
          // at this point the xwiki-macro-insert deals with the macro insertion in the rich editor.
          return '';
        }
      };
    }

    function updateConfig(editor) {
      editor.config.mentions = editor.config.mentions || [];
      editor.config.mentions.push(getUserMentionsConfig(editor));
    }

    ckeditor.on('instanceCreated', function(event) {
      // The editor instance was created but it not yet initialized. Unfortunately the configuration object passed when
      // the instance was created has not been merged with the global configuration yet.
      event.editor.once('configLoaded', function(event) {
        // The editor configuration has been loaded (the instance configuration has been merged with the global
        // configuration) but the editor has not been fully initialized yet so we can modify the configuration.
        updateConfig(event.editor);
      });
    });
  });
});
