(function() {
  'use strict';

  var meta = document.querySelector('meta[name="ux-toolkit-attachment-preview"]');
  if (!meta) {
    return;
  }

  var config;
  try {
    config = JSON.parse(meta.getAttribute('content') || '{}');
  } catch (error) {
    return;
  }

  var imagePattern = /\.(?:png|jpe?g|gif|bmp)$/i;
  var pdfPattern = /\.pdf$/i;
  var attachmentPattern = /^(.*\/attachments\/)(?:download\/)?(\d+)(?:\/(.*))?$/;
  var overlay;
  var titleElement;
  var bodyElement;
  var previousButton;
  var nextButton;
  var counterElement;
  var downloadLink;
  var activeItems = [];
  var activeIndex = 0;
  var returnFocus;

  function decoded(value) {
    try {
      return decodeURIComponent(value);
    } catch (error) {
      return value;
    }
  }

  function filenameFrom(anchor, pathFilename) {
    var image = anchor.querySelector('img[alt]');
    var candidates = [
      pathFilename && decoded(pathFilename.split('/').pop()),
      anchor.getAttribute('data-filename'),
      image && image.getAttribute('alt'),
      anchor.getAttribute('title'),
      anchor.textContent && anchor.textContent.trim()
    ];

    return candidates.find(function(candidate) {
      return candidate && (imagePattern.test(candidate) || pdfPattern.test(candidate));
    }) || '';
  }

  function itemFor(anchor) {
    if (!anchor || anchor.hasAttribute('download') || anchor.matches('.icon-download, .delete')) {
      return null;
    }

    // Let an already active legacy lightbox own links it has explicitly prepared.
    if (window.jQuery && window.jQuery.fancybox &&
        anchor.matches('[data-fancybox], .lightbox, .lightbox_preview')) {
      return null;
    }

    var url;
    try {
      url = new URL(anchor.href, window.location.href);
    } catch (error) {
      return null;
    }

    if (url.origin !== window.location.origin) {
      return null;
    }

    var match = url.pathname.match(attachmentPattern);
    if (!match) {
      return null;
    }

    var filename = filenameFrom(anchor, match[3]);
    var type = pdfPattern.test(filename) ? 'pdf' : (imagePattern.test(filename) ? 'image' : '');
    if (!type || (type === 'image' && !config.images) || (type === 'pdf' && !config.pdfs)) {
      return null;
    }

    var encodedFilename = filename.split('/').map(encodeURIComponent).join('/');
    return {
      anchor: anchor,
      filename: filename,
      type: type,
      url: match[1] + 'download/' + match[2] + '/' + encodedFilename
    };
  }

  function galleryRoot(anchor) {
    return anchor.closest('.attachments, .journal, table.files, td.attachments, .wiki') || document;
  }

  function decoratePdfThumbnail(anchor) {
    if (!config.pdfs || !anchor) {
      return;
    }

    var thumbnail = anchor.closest('.thumbnail');
    var image = anchor.querySelector('img');
    if (!thumbnail || !image || anchor.querySelector('.ux-attachment-preview__pdf-tile')) {
      return;
    }

    var url;
    try {
      url = new URL(anchor.href, window.location.href);
    } catch (error) {
      return;
    }

    var match = url.pathname.match(attachmentPattern);
    var filename = match && filenameFrom(anchor, match[3]);
    if (!filename || !pdfPattern.test(filename)) {
      return;
    }

    var tile = document.createElement('span');
    tile.className = 'ux-attachment-preview__pdf-tile';
    tile.setAttribute('aria-hidden', 'true');

    var typeLabel = document.createElement('span');
    typeLabel.className = 'ux-attachment-preview__pdf-type';
    typeLabel.textContent = 'PDF';

    var filenameLabel = document.createElement('span');
    filenameLabel.className = 'ux-attachment-preview__pdf-filename';
    filenameLabel.textContent = filename;

    tile.appendChild(typeLabel);
    tile.appendChild(filenameLabel);
    anchor.setAttribute('data-filename', filename);
    image.replaceWith(tile);
    anchor.setAttribute('aria-label', config.previewLabel + ': ' + filename);
  }

  function decorateAttachmentLinks(root) {
    Array.prototype.forEach.call(root.querySelectorAll('a[href]'), function(anchor) {
      decoratePdfThumbnail(anchor);
      if (itemFor(anchor)) {
        anchor.classList.add('ux-attachment-preview-link');
      }
    });
  }

  function itemsFor(anchor) {
    if (!config.gallery) {
      return [itemFor(anchor)];
    }

    var seen = {};
    return Array.prototype.map.call(galleryRoot(anchor).querySelectorAll('a[href]'), itemFor)
      .filter(function(item) {
        if (!item || seen[item.url]) {
          return false;
        }
        seen[item.url] = true;
        return true;
      });
  }

  function button(className, label, text) {
    var element = document.createElement('button');
    element.type = 'button';
    element.className = 'ux-attachment-preview__button ' + className;
    element.setAttribute('aria-label', label);
    element.title = label;
    element.textContent = text;
    return element;
  }

  function ensureOverlay() {
    if (overlay) {
      return;
    }

    overlay = document.createElement('div');
    overlay.className = 'ux-attachment-preview';
    overlay.hidden = true;
    overlay.innerHTML = '<div class="ux-attachment-preview__dialog" role="dialog" aria-modal="true" aria-labelledby="ux-attachment-preview-title">' +
      '<div class="ux-attachment-preview__header">' +
      '<h2 class="ux-attachment-preview__title" id="ux-attachment-preview-title"></h2>' +
      '</div>' +
      '<div class="ux-attachment-preview__body"></div>' +
      '<div class="ux-attachment-preview__toolbar"></div>' +
      '</div>';

    titleElement = overlay.querySelector('.ux-attachment-preview__title');
    bodyElement = overlay.querySelector('.ux-attachment-preview__body');
    var header = overlay.querySelector('.ux-attachment-preview__header');
    var toolbar = overlay.querySelector('.ux-attachment-preview__toolbar');

    previousButton = button('ux-attachment-preview__previous', config.previousLabel, '\u2039');
    nextButton = button('ux-attachment-preview__next', config.nextLabel, '\u203a');
    counterElement = document.createElement('span');
    counterElement.className = 'ux-attachment-preview__counter';
    counterElement.setAttribute('aria-live', 'polite');
    downloadLink = document.createElement('a');
    downloadLink.className = 'ux-attachment-preview__button ux-attachment-preview__download';
    downloadLink.textContent = config.downloadLabel;
    downloadLink.title = config.downloadLabel;
    downloadLink.setAttribute('download', '');
    var closeButton = button('ux-attachment-preview__close', config.closeLabel, '\u00d7');

    header.appendChild(closeButton);
    toolbar.appendChild(previousButton);
    toolbar.appendChild(counterElement);
    toolbar.appendChild(nextButton);
    toolbar.appendChild(downloadLink);
    document.body.appendChild(overlay);

    previousButton.addEventListener('click', function() { show(activeIndex - 1); });
    nextButton.addEventListener('click', function() { show(activeIndex + 1); });
    closeButton.addEventListener('click', close);
    overlay.addEventListener('click', function(event) {
      if (event.target === overlay) {
        close();
      }
    });
  }

  function show(index) {
    var item = activeItems[index];
    if (!item) {
      return;
    }

    activeIndex = index;
    titleElement.textContent = item.filename;
    bodyElement.replaceChildren();

    if (item.type === 'pdf') {
      var frame = document.createElement('iframe');
      frame.className = 'ux-attachment-preview__pdf';
      frame.src = item.url;
      frame.title = config.previewLabel + ': ' + item.filename;
      bodyElement.appendChild(frame);
    } else {
      var image = document.createElement('img');
      image.className = 'ux-attachment-preview__image';
      image.src = item.url;
      image.alt = item.filename;
      image.addEventListener('error', function() {
        bodyElement.innerHTML = '';
        var message = document.createElement('p');
        message.className = 'ux-attachment-preview__error';
        message.textContent = config.errorMessage;
        bodyElement.appendChild(message);
      });
      bodyElement.appendChild(image);
    }

    var galleryVisible = config.gallery && activeItems.length > 1;
    previousButton.hidden = !galleryVisible;
    nextButton.hidden = !galleryVisible;
    counterElement.hidden = !galleryVisible;
    previousButton.disabled = activeIndex === 0;
    nextButton.disabled = activeIndex === activeItems.length - 1;
    counterElement.textContent = (activeIndex + 1) + ' / ' + activeItems.length;
    downloadLink.hidden = !config.download;
    downloadLink.href = item.url;
    downloadLink.setAttribute('download', item.filename);
  }

  function open(anchor) {
    var selected = itemFor(anchor);
    if (!selected) {
      return false;
    }

    ensureOverlay();
    activeItems = itemsFor(anchor);
    activeIndex = Math.max(0, activeItems.findIndex(function(item) { return item.url === selected.url; }));
    returnFocus = anchor;
    overlay.hidden = false;
    document.documentElement.classList.add('ux-attachment-preview-open');
    show(activeIndex);
    overlay.querySelector('.ux-attachment-preview__close').focus();
    return true;
  }

  function close() {
    if (!overlay || overlay.hidden) {
      return;
    }

    overlay.hidden = true;
    bodyElement.replaceChildren();
    document.documentElement.classList.remove('ux-attachment-preview-open');
    if (returnFocus) {
      returnFocus.focus();
    }
  }

  document.addEventListener('click', function(event) {
    if (event.defaultPrevented || event.button !== 0 || event.ctrlKey || event.metaKey || event.shiftKey || event.altKey) {
      return;
    }

    var anchor = event.target.closest && event.target.closest('a[href]');
    if (open(anchor)) {
      event.preventDefault();
    }
  });

  document.addEventListener('keydown', function(event) {
    if (!overlay || overlay.hidden) {
      return;
    }

    if (event.key === 'Escape') {
      close();
    } else if (event.key === 'ArrowLeft' && !previousButton.hidden && activeIndex > 0) {
      show(activeIndex - 1);
    } else if (event.key === 'ArrowRight' && !nextButton.hidden && activeIndex < activeItems.length - 1) {
      show(activeIndex + 1);
    }
  });

  document.addEventListener('DOMContentLoaded', function() {
    decorateAttachmentLinks(document);
  });
})();
