define('xwiki-pdf-export-messages', {
  keys: [
    'core.export.pdf.options.title',
    'export.pdf.options.template',
    'export.pdf.options.template.hint',
    'export.pdf.options.loadFailure',
    'export.pdf.modal.close',
    'export.pdf.inProgress'
  ]
});

define('xwiki-pdf-export-config', ['jquery'], function($) {
  try {
    return JSON.parse($('#pdfExportConfig').text());
  } catch (e) {
    console.error(e);
    return {};
  }
});

require(['jquery', 'xwiki-pdf-export-config', 'xwiki-l10n!xwiki-pdf-export-messages', 'bootstrap'], function($, config, l10n) {
  const pdfExportOptionsModal = $(`
    <form class="modal xform" id="pdfExportOptions" tabindex="-1" role="dialog"
        aria-labelledby="pdfExportOptionsTitle">
      <div class="modal-dialog" role="document">
        <div class="modal-content">
          <div class="modal-header">
            <button type="button" class="close" data-dismiss="modal">
              <span aria-hidden="true">&times;</span>
            </button>
            <h4 class="modal-title" id="pdfExportOptionsTitle"></h4>
          </div>
          <div class="modal-body loading"></div>
          <div class="modal-footer"></div>
        </div>
      </div>
    </form>
  `);
  pdfExportOptionsModal.find('button.close').attr({
    'title': l10n['export.pdf.modal.close'],
    'aria-label': l10n['export.pdf.modal.close']
  });
  pdfExportOptionsModal.find('.modal-title').text(l10n['core.export.pdf.options.title']);
  // Fade only on hide. We don't want to fade on show because we want the transition from the Export modal (previous
  // step) to be fast and smooth.
  pdfExportOptionsModal.on('shown.bs.modal', function() {
    // We need the fade CSS class name on the backdrop also, otherwise we get an ugly flicker when the modal is hidden.
    pdfExportOptionsModal.add('.modal-backdrop.in').addClass('fade');
  });

  const templateOption = $(`
    <dl>
      <dt>
        <label for="pdfTemplate"></label>
        <span class="xHint"></span>
      </dt>
      <dd>
        <select id="pdfTemplate" name="template"></select>
      </dd>
    </dl>
  `);
  templateOption.find('label').text(l10n['export.pdf.options.template']);
  templateOption.find('.xHint').text(l10n['export.pdf.options.template.hint']);
  if (Array.isArray(config.templates)) {
    const select = templateOption.find('select');
    config.templates.forEach(template => {
      $('<option></option>').text(template.label).attr('value', template.value).appendTo(select);
    });
    // Select the first option by default.
    select.find('option').first().attr('selected', 'selected');
  }

  const openPDFOptionsModal = function(url) {
    // Disable the animation on show in order to have a smooth transition from the previous modal.
    pdfExportOptionsModal.removeClass('fade').modal();
    if (!pdfExportOptionsModal.find('.modal-body').hasClass('loading')) {
      // The modal is already loaded and initialized.
      return;
    }
    $('<div></div>').load(url + ' #pdfExportOptions', function() {
      const form = $(this).find('#pdfExportOptions');
      if (form.length) {
        form.find('.buttons').appendTo(pdfExportOptionsModal.find('.modal-footer'));
        // Hide useless options.
        form.find('#comments, #attachments').closest('dt').hide().parent().css('margin-bottom', '0');
        // Add the template option.
        form.find('dl').prepend(templateOption.contents());
        pdfExportOptionsModal.attr('action', form.attr('action'));
        pdfExportOptionsModal.find('.modal-body').removeClass('loading').append(form.contents());
      } else {
        new XWiki.widgets.Notification(l10n['export.pdf.options.loadFailure'], 'error');
        pdfExportOptionsModal.modal('hide');
      }
    });
  };

  const exportToPDF = function(extraQueryString) {
    return new Promise((resolve, reject) => {
      const iframe = $('<iframe/>').css({
        // The load event is not fired if we hide it completely with display:none.
        'visibility': 'hidden',
        // Use the same width as the main window because the CSS or JavaScript code could rely on it (we want the result
        // to look exactly as if the user has opened the export URL directly).
        'width': $(window).width()
      }).on('load', () => {
        iframe[0].contentWindow.require(['xwiki-page-ready'], function(pageReady) {
          pageReady.afterPageReady(() => {
            // Trigger the print only after all page ready callbacks were executed, because the print preview is
            // initialized as a page ready callback.
            pageReady.afterPageReady(() => {
              iframe[0].contentWindow.print();
              iframe.remove();
              resolve();
            });
          });
        });
      });
      const exportURL = XWiki.currentDocument.getURL('export', $.param({
        format: 'html-print',
        xpage: 'get',
        outputSyntax: 'plain',
        // Asynchronous rendering is disabled by default on the export action so we need to force it.
        async: true,
        sheet: 'XWiki.PDFExport.Sheet'
      // We add the hash (document fragment) because it can contain information used by the JavaScript code (e.g. the
      // state of the live table component).
      })) + '&' + extraQueryString + window.location.hash;
      iframe.attr('src', exportURL).appendTo($('body'));
    });
  };

  pdfExportOptionsModal.on('submit', event => {
    event.preventDefault();
    $('body').css('cursor', 'wait');
    const notification = new XWiki.widgets.Notification(l10n['export.pdf.inProgress'], 'inprogress');
    pdfExportOptionsModal.find('input[type=submit]').prop('disabled', true);
    // We add the current value of the query string after the PDF export options because we want to export the current
    // state of the page (the query string can hold for instance the state of the live data component).
    const queryString = pdfExportOptionsModal.serialize() + '&' + window.location.search.substring(1);
    exportToPDF(queryString).finally(() => {
      pdfExportOptionsModal.find('input[type=submit]').prop('disabled', false);
      notification.hide();
      $('body').css('cursor', '');
    });
  });

  pdfExportOptionsModal.on('click', 'a.secondary.button', event => {
    event.preventDefault();
    pdfExportOptionsModal.modal('hide');
  });

  $('#exportModal a[href*="xpage=pdfoptions"]').on('click', event => {
    event.preventDefault();
    // Show the PDF Export Options modal only after the Export modal is completely hidden, otherwise the code that hides
    // the Export modal can revert changes done by the code that shows the PDF Export Options modal (e.g. we loose the
    // 'modal-open' CSS class on the BODY element which is needed in order to hide the page scrollbars).
    $('#exportModal').one('hidden.bs.modal', () => {
      // Enable the animation back for the next time the Export modal is shown.
      $('#exportModal').addClass('fade');
      // Remove the qs parameter because:
      // * the PDF export options modal is loaded only once (per page load) and the query string can change afterwards
      // * the query string can change after the page is loaded (e.g. that's how the live data component saves its state
      //   in the URL) and we want to use the query string value at the moment when the PDF export is triggered
      const url = $(event.target).attr('href').replace(/([?&])qs=[^&#]*/, '$1');
      openPDFOptionsModal(url);
    // Disable the animation when moving to the next step (PDF Export Options) in order to have a smooth transition.
    }).removeClass('fade').modal('hide');
  });
});
