// Copyright (C) 2020 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Handles registration, unregistration and lifecycle of the service worker.
// This class contains only the controlling logic, all the code in here runs in
// the main thread, not in the service worker thread.
// The actual service worker code is in src/service_worker.
// Design doc: http://go/perfetto-offline.

import {reportError} from '../base/logging';
import {ignoreCacheUnactionableErrors} from '../common/errors';

import {globals} from './globals';

// We use a dedicated |caches| object to share a global boolean beween the main
// thread and the SW. SW cannot use local-storage or anything else other than
// IndexedDB (which would be overkill).
const BYPASS_ID = 'BYPASS_SERVICE_WORKER';

class BypassCache {
  static async isBypassed(): Promise<boolean> {
    try {
      return await caches.has(BYPASS_ID);
    } catch (e) {
      return ignoreCacheUnactionableErrors(e, false);
    }
  }

  static async setBypass(bypass: boolean): Promise<void> {
    try {
      if (bypass) {
        await caches.open(BYPASS_ID);
      } else {
        await caches.delete(BYPASS_ID);
      }
    } catch (e) {
      ignoreCacheUnactionableErrors(e, undefined);
    }
  }
}

export class ServiceWorkerController {
  private _initialWorker: ServiceWorker|null = null;
  private _bypassed = false;
  private _installing = false;

  // Caller should reload().
  async setBypass(bypass: boolean) {
    if (!('serviceWorker' in navigator)) return;  // Not supported.
    this._bypassed = bypass;
    if (bypass) {
      await BypassCache.setBypass(true);  // Create the entry.
      for (const reg of await navigator.serviceWorker.getRegistrations()) {
        await reg.unregister();
      }
    } else {
      await BypassCache.setBypass(false);
      if (window.localStorage) {
        window.localStorage.setItem('bypassDisabled', '1');
      }
      this.install();
    }
    globals.rafScheduler.scheduleFullRedraw();
  }

  onStateChange(sw: ServiceWorker) {
    globals.rafScheduler.scheduleFullRedraw();
    if (sw.state === 'installing') {
      this._installing = true;
    } else if (sw.state === 'activated') {
      this._installing = false;
      // Don't show the notification if the site was served straight
      // from the network (e.g., on the very first visit or after
      // Ctrl+Shift+R). In these cases, we are already at the last
      // version.
      if (sw !== this._initialWorker && this._initialWorker) {
        globals.frontendLocalState.newVersionAvailable = true;
      }
    }
  }

  monitorWorker(sw: ServiceWorker|null) {
    if (!sw) return;
    sw.addEventListener('error', (e) => reportError(e));
    sw.addEventListener('statechange', () => this.onStateChange(sw));
    this.onStateChange(sw);  // Trigger updates for the current state.
  }

  async install() {
    if (!('serviceWorker' in navigator)) return;  // Not supported.

    if (location.pathname !== '/') {
      // Disable the service worker when the UI is loaded from a non-root URL
      // (e.g. from the CI artifacts GCS bucket). Supporting the case of a
      // nested index.html is too cumbersome and has no benefits.
      return;
    }

    // If this is localhost disable the service worker by default, unless the
    // user manually re-enabled it (in which case bypassDisabled = '1').
    const hostname = location.hostname;
    const isLocalhost = ['127.0.0.1', '::1', 'localhost'].includes(hostname);
    const bypassDisabled = window.localStorage &&
        window.localStorage.getItem('bypassDisabled') === '1';
    if (isLocalhost && !bypassDisabled) {
      await this.setBypass(true);  // Will cause the check below to bail out.
    }

    if (await BypassCache.isBypassed()) {
      this._bypassed = true;
      console.log('Skipping service worker registration, disabled by the user');
      return;
    }
    // In production cases versionDir == VERSION. We use this here for ease of
    // testing (so we can have /v1.0.0a/ /v1.0.0b/ even if they have the same
    // version code).
    const versionDir = globals.root.split('/').slice(-2)[0];
    const swUri = `/service_worker.js?v=${versionDir}`;
    navigator.serviceWorker.register(swUri).then((registration) => {
      this._initialWorker = registration.active;

      // At this point there are two options:
      // 1. This is the first time we visit the site (or cache was cleared) and
      //    no SW is installed yet. In this case |installing| will be set.
      // 2. A SW is already installed (though it might be obsolete). In this
      //    case |active| will be set.
      this.monitorWorker(registration.installing);
      this.monitorWorker(registration.active);

      // Setup the event that shows the "Updated to v1.2.3" notification.
      registration.addEventListener('updatefound', () => {
        this.monitorWorker(registration.installing);
      });
    });
  }

  get bypassed() {
    return this._bypassed;
  }
  get installing() {
    return this._installing;
  }
}
