(function () {
  'use strict';

  const versions = Object.freeze({ app: '0.12.14', jquery: '4.0.0', jqueryUi: '1.14.2' });
  const steps = ['jquery', 'jquery-ui', 'modules', 'server', 'routes', 'location'];
  const screen = document.getElementById('bootstrap-screen');
  const progress = document.getElementById('bootstrap-progress');
  const errorBox = document.getElementById('bootstrap-error');
  const retry = document.getElementById('bootstrap-retry');
  const enter = document.getElementById('bootstrap-enter');
  const readyText = document.getElementById('bootstrap-ready');
  const cleanupStatus = document.getElementById('storage-cleanup-status');
  let ready = false;

  const versioned = path => `${path}${path.includes('?') ? '&' : '?'}v=${encodeURIComponent(versions.app)}`;

  function mark(step, state) {
    const item = document.querySelector(`[data-step="${step}"]`);
    if (!item) return;
    item.classList.remove('done', 'failed');
    item.classList.add(state);
    progress.value = document.querySelectorAll('#bootstrap-steps .done').length;
  }

  function loadScript(src, test) {
    return new Promise((resolve, reject) => {
      const script = document.createElement('script');
      script.src = versioned(src);
      script.async = false;
      script.onload = () => {
        if (test && !test()) reject(new Error(`Selbsttest fehlgeschlagen: ${src}`));
        else resolve();
      };
      script.onerror = () => reject(new Error(`Datei konnte nicht geladen werden: ${src}`));
      document.head.appendChild(script);
    });
  }

  function initializeJqueryUi() {
    const $ = globalThis.jQuery;
    $('#bootstrap-retry').button({ icon: 'ui-icon-refresh' });
    $('#bootstrap-enter').button();
    $('.back-button').button();
    $('#clear-route-search').button({ icon: 'ui-icon-close', showLabel: false });
    $('#slide-prev').button();
    $('#slide-next').button();
  }

  function updateCleanupProgress(removed, total) {
    cleanupStatus.textContent = `Entferne alte Streckendaten aus dem Speicher (${removed} / ${total})`;
    cleanupStatus.hidden = false;
  }

  async function cleanupOldProgress() {
    cleanupStatus.hidden = true;
    await globalThis.Wegwichtel.PrivacyStorage.cleanupExpired(updateCleanupProgress);
  }

  function isActivation(event) {
    if (event.type === 'keydown') return event.key === 'Enter' || event.key === ' ';
    if (event.type !== 'pointerup') return false;
    if (event.isPrimary === false) return false;
    return event.pointerType !== 'mouse' || event.button === 0;
  }

  function openApplication(event) {
    if (!ready || !isActivation(event)) return;
    if (event.target !== enter && event.target.closest('button, input, label, a, dialog')) return;

    event.preventDefault();
    screen.hidden = true;
    document.getElementById('app-shell').hidden = false;
    globalThis.Wegwichtel.App.navigate('#routes-page', { replace: true });
  }

  function showReadyState() {
    ready = true;
    screen.setAttribute('aria-busy', 'false');
    screen.classList.add('ready');
    readyText.hidden = false;
    enter.hidden = false;
    enter.focus();
  }

  async function boot() {
    ready = false;
    screen.setAttribute('aria-busy', 'true');
    screen.classList.remove('ready');
    readyText.hidden = true;
    enter.hidden = true;
    errorBox.hidden = true;
    retry.hidden = true;

    try {
      await cleanupOldProgress();

      await loadScript(
        `vendor/jquery/jquery-${versions.jquery}.min.js`,
        () => globalThis.jQuery?.fn?.jquery === versions.jquery
      );
      mark('jquery', 'done');

      await loadScript(
        `vendor/jquery-ui/jquery-ui-${versions.jqueryUi}.min.js`,
        () => globalThis.jQuery?.ui?.version === versions.jqueryUi
      );
      initializeJqueryUi();
      mark('jquery-ui', 'done');

      for (const module of ['config', 'api-client', 'distance', 'geolocation', 'orientation', 'slideshow', 'audio-player', 'vibration', 'app']) {
        await loadScript(`js/${module}.js`, () => Boolean(globalThis.Wegwichtel));
      }
      mark('modules', 'done');

      await globalThis.Wegwichtel.App.initialize({ markStep: mark });
      showReadyState();
    } catch (error) {
      console.error(error);
      const current = steps.find(step => !document.querySelector(`[data-step="${step}"]`)?.classList.contains('done'));
      if (current) mark(current, 'failed');
      errorBox.textContent = error.message;
      errorBox.hidden = false;
      retry.hidden = false;
    }
  }

  function retryBoot(event) {
    if (!isActivation(event)) return;
    event.preventDefault();
    event.stopPropagation();
    location.reload();
  }

  retry.addEventListener('pointerup', retryBoot);
  retry.addEventListener('keydown', retryBoot);
  enter.addEventListener('pointerup', openApplication);
  enter.addEventListener('keydown', openApplication);
  screen.addEventListener('pointerup', openApplication);
  boot();
}());
