import { Injectable } from '@angular/core';

import { environment } from '../../environments/environment';
import { Logger } from 'app/shared/logger.service';

@Injectable()
/**
 * Google Analytics Service - captures app behaviors and sends them to Google Analytics (GA).
 * Presupposes that GA script has been loaded from a script on the host web page.
 * Associates data with a GA "property" from the environment (`gaId`).
 */
export class GaService {
  // ms to wait before acquiring window.ga after analytics library loads
  // empirically determined to allow time for e2e test setup
  static initializeDelay = 1000;

  private previousUrl: string;
  private ga: (...rest: any[]) => void;

  constructor(private logger: Logger) {
    this.initializeGa();
    this.ga('create', environment['gaId'] , 'auto');
  }

  locationChanged(url: string) {
    this.sendPage(url);
  }

  sendPage(url: string) {
    // Won't re-send if the url (including fragment) hasn't changed.
    // TODO: Perhaps we don't want to track clicks on in-page links.
    // Could easily report only when the page (base url) changes.
    if (url === this.previousUrl) { return; }
    this.previousUrl = url;
    this.ga('set', 'page', '/' + url);
    this.ga('send', 'pageview');
  }

  // These gyrations are necessary to make the service e2e testable
  // and to disable ga tracking during e2e tests.
  private initializeGa() {
    const ga = window['ga'];
    if (ga) {
      // Queue commands until GA analytics script has loaded.
      const gaQueue: any[][] = [];
      this.ga = (...rest: any[]) => { gaQueue.push(rest); };

      // Then send queued commands to either real or e2e test ga();
      // after waiting to allow possible e2e test to replace global ga function
      ga(() => setTimeout(() => {
        // this.logger.log('GA fn:', window['ga'].toString());
        this.ga = window['ga'];
        gaQueue.forEach((command) => this.ga.apply(null, command));
      }, GaService.initializeDelay));

    } else {
      // delegate `ga` calls to the logger if no ga installed
      this.ga = (...rest: any[]) => { this.logger.log('ga:', rest); };
    }
  }

}
