import { Injectable } from '@angular/core';
import { Observable, Subject, merge } from 'rxjs';
import { switchMap, shareReplay } from 'rxjs/operators';

import { NativeEventSource, EventSourcePolyfill } from 'event-source-polyfill';
const EventSource = NativeEventSource || EventSourcePolyfill;
// OR: may also need to set as global property
// global.EventSource =  NativeEventSource || EventSourcePolyfill;

const CACHE_SIZE = 1;

// Creates a cache of requests that are automatically busted based on server sent events

@Injectable({
  providedIn: 'root'
})
export class UberCacheService {
  private cache$: CacheStore;

  constructor() {
    this.cache$ = {};
  }

  public getRequest<T>(request: ()=>Observable<T>, eventUrl: string, eventName: string): Observable<T> {
    if (!this.cache$[eventUrl]) {
      const updateStream = this.createUpdateStream(eventUrl, eventName);
      const initialCurrentUser$ = request();
      const reload$ = updateStream.pipe(switchMap(() => request()));
      const newCache = merge(initialCurrentUser$, reload$).pipe(shareReplay(CACHE_SIZE));
      this.cache$[eventUrl] = {
        cache: newCache,
        stream: updateStream
      };
    }
    return this.cache$[eventUrl].cache;
  }

  private createUpdateStream(eventUrl: string, eventName: string) {
    const eventStream = new Subject<void>();
    const es = new EventSource(eventUrl);
    es.addEventListener(eventName, (evt: StreamEvent) => {
      console.log(evt.data);
      eventStream.next();
    });
    return eventStream;
  }
}

interface StreamEvent {
  data?: string;
  event?: string;
  id?: string;
  retry?: number;
}

interface CacheStore {
  [name: string]: CacheTools;
}

interface CacheTools {
  cache: Observable<any>;
  stream: Subject<void>;
}
