import { BehaviorSubject, Observable } from 'rxjs';

import { ModuleConfig } from '../config/module-config';
import { _MODULE_CONFIG } from '../config/token';

export abstract class WebStorageService {
  private __storage: Storage;
  private __subjects: Map<string, BehaviorSubject<any>>;

  /**
   * Constructor
   */
  constructor(storage: Storage) {
    this.__storage = storage;
    this.__subjects = new Map<string, BehaviorSubject<any>>();
  }

  // -----------------------------------------------------------------------------------------------------
  // @ Accessors
  // -----------------------------------------------------------------------------------------------------

  // -----------------------------------------------------------------------------------------------------
  // @ Public methods
  // -----------------------------------------------------------------------------------------------------
  /**
   * watch data of given key
   * @param key
   * @param defaultValue
   */
  watch(key: string, defaultValue: any = null): Observable<any> {
    if (!this.__subjects.has(key)) {
      this.__subjects.set(key, new BehaviorSubject<any>(defaultValue));
    }
    let item = this.__storage.getItem(key);
    if (item !== null) {
      item = JSON.parse(item);
    }
    (this.__subjects.get(key) as BehaviorSubject<any>).next(item);
    return (this.__subjects.get(key) as BehaviorSubject<any>).asObservable();
  }

  /**
   * get data of given key
   * @param key
   */
  get(key: string): any {
    let item = this.__storage.getItem(key);
    if (item !== null) {
      item = JSON.parse(item);
    }
    return item;
  }

  /**
   * set value on given key
   * @param key
   * @param value
   */
  set(key: string, value: any) {
    this.__storage.setItem(key, JSON.stringify(value));
    if (!this.__subjects.has(key)) {
      this.__subjects.set(key, new BehaviorSubject<any>(value));
      (this.__subjects.get(key) as BehaviorSubject<any>).next(value);
    } else {
      (this.__subjects.get(key) as BehaviorSubject<any>).next(value);
    }
  }

  /**
   * remove given key
   * @param key
   */
  remove(key: string) {
    if (this.__subjects.has(key)) {
      (this.__subjects.get(key) as BehaviorSubject<any>).complete();
      this.__subjects.delete(key);
    }
    this.__storage.removeItem(key);
  }

  /**
   * clear all available keys
   */
  clear() {
    this.__subjects.clear();
    this.__storage.clear();
  }
}
