(function() {
  var currentPage = '';

  function messageFor(error) {
    if (!error) {
      return 'unknown error';
    }
    if (error.message) {
      return error.message;
    }
    return String(error);
  }

  function setPage(pageName) {
    currentPage = pageName || '';
    document.documentElement.setAttribute('data-crank-page', currentPage || 'unknown');
  }

  function markBootstrapState(pageName, status, details) {
    document.documentElement.setAttribute('data-crank-bootstrap-page', pageName || currentPage || 'unknown');
    document.documentElement.setAttribute('data-crank-bootstrap-state', status);
    if (status === 'error' && details) {
      document.documentElement.setAttribute('data-crank-bootstrap-error', details);
      return;
    }
    document.documentElement.removeAttribute('data-crank-bootstrap-error');
  }

  function report(stage, error, pageName) {
    var resolvedPage = pageName || currentPage || 'unknown';
    console.error('[CrankUI][' + resolvedPage + '][' + stage + ']', error);
    window.dispatchEvent(new CustomEvent('crank:ui-error', {
      detail: {
        page: resolvedPage,
        stage: stage,
        message: messageFor(error),
      },
    }));
  }

  function bootstrap(pageName, init) {
    function run() {
      setPage(pageName);
      markBootstrapState(pageName, 'pending');
      try {
        var result = init();
        if (result && typeof result.then === 'function') {
          result.then(function() {
            markBootstrapState(pageName, 'ready');
          }).catch(function(error) {
            markBootstrapState(pageName, 'error', messageFor(error));
            report('bootstrap', error, pageName);
          });
          return;
        }
        markBootstrapState(pageName, 'ready');
      } catch (error) {
        markBootstrapState(pageName, 'error', messageFor(error));
        report('bootstrap', error, pageName);
      }
    }

    if (document.readyState === 'loading') {
      document.addEventListener('DOMContentLoaded', run, { once: true });
      return;
    }
    run();
  }

  function ensureTestId(element, value) {
    if (!element || !value) {
      return;
    }
    element.setAttribute('data-testid', value);
  }

  function ensureShellTestIds() {
    document.querySelectorAll('.nav-avatar').forEach(function(element) {
      ensureTestId(element, 'shell-avatar');
    });
    document.querySelectorAll('.user-dropdown-name').forEach(function(element) {
      ensureTestId(element, 'shell-user-name');
    });
    document.querySelectorAll('.user-dropdown-role').forEach(function(element) {
      ensureTestId(element, 'shell-user-role');
    });
    ensureTestId(document.getElementById('ws-current-name'), 'shell-workspace-name');
  }

  window.addEventListener('error', function(event) {
    if (!currentPage) {
      return;
    }
    report('runtime', event.error || new Error(event.message || 'window error'));
  });

  window.addEventListener('unhandledrejection', function(event) {
    if (!currentPage) {
      return;
    }
    report('unhandledrejection', event.reason || new Error('unhandled rejection'));
  });

  window.CrankDiagnostics = {
    bootstrap: bootstrap,
    ensureTestId: ensureTestId,
    ensureShellTestIds: ensureShellTestIds,
    report: report,
    setPage: setPage,
  };
}());
