app.ServiceWorker = class ServiceWorker extends Events {
  static isEnabled() {
    return !!navigator.serviceWorker && app.config.service_worker_enabled;
  }

  constructor() {
    super();
    this.onStateChange = this.onStateChange.bind(this);
    this.registration = null;
    this.notifyUpdate = true;

    navigator.serviceWorker
      .register(app.config.service_worker_path, { scope: "/" })
      .then(
        (registration) => this.updateRegistration(registration),
        (error) => console.error("Could not register service worker:", error),
      );
  }

  update() {
    if (!this.registration) {
      return;
    }
    this.notifyUpdate = true;
    return this.registration.update().catch(() => {});
  }

  updateInBackground() {
    if (!this.registration) {
      return;
    }
    this.notifyUpdate = false;
    return this.registration.update().catch(() => {});
  }

  reload() {
    return this.updateInBackground().then(() => app.reboot());
  }

  updateRegistration(registration) {
    this.registration = registration;
    $.on(this.registration, "updatefound", () => this.onUpdateFound());
  }

  onUpdateFound() {
    if (this.installingRegistration) {
      $.off(this.installingRegistration, "statechange", this.onStateChange);
    }
    this.installingRegistration = this.registration.installing;
    $.on(this.installingRegistration, "statechange", this.onStateChange);
  }

  onStateChange() {
    if (
      this.installingRegistration &&
      this.installingRegistration.state === "installed" &&
      navigator.serviceWorker.controller
    ) {
      this.installingRegistration = null;
      this.onUpdateReady();
    }
  }

  onUpdateReady() {
    if (this.notifyUpdate) {
      this.trigger("updateready");
    }
  }
};