(function (ns) {
  'use strict';

  let listener = null;
  const eventNames = ['deviceorientationabsolute', 'deviceorientation'];
  let callback = null;

  function normalizeDegrees(value) {
    return (value % 360 + 360) % 360;
  }

  function readHeading(event) {
    if (Number.isFinite(event.webkitCompassHeading)) {
      return normalizeDegrees(event.webkitCompassHeading);
    }

    if ((event.absolute || event.type === 'deviceorientationabsolute') && Number.isFinite(event.alpha)) {
      return normalizeDegrees(360 - event.alpha);
    }

    return null;
  }

  async function requestPermission() {
    const orientation = globalThis.DeviceOrientationEvent;
    if (!orientation) return false;

    if (typeof orientation.requestPermission === 'function') {
      return (await orientation.requestPermission()) === 'granted';
    }

    return true;
  }

  ns.Orientation = {
    async start(onHeading) {
      this.stop();
      callback = onHeading;

      let permitted = false;
      try {
        permitted = await requestPermission();
      } catch {
        permitted = false;
      }

      if (!permitted) return false;

      listener = event => {
        const heading = readHeading(event);
        if (heading != null) callback?.(heading);
      };

      eventNames.forEach(name => globalThis.addEventListener(name, listener, true));
      return true;
    },

    stop() {
      if (listener) eventNames.forEach(name => globalThis.removeEventListener(name, listener, true));
      listener = null;
      callback = null;
    }
  };
}(globalThis.Wegwichtel));
