import { Injectable } from '@angular/core';
import { Logger, LogLevel } from '@core/logger';
import { Store } from '@ngrx/store';
import { UserStateService } from '@swagger/isa';
import { debounceTime, switchMap } from 'rxjs/operators';
import { RootState } from './root.state';
import packageInfo from 'package';
import { environment } from '../../environments/environment';

@Injectable({ providedIn: 'root' })
export class RootStateService {
  static LOCAL_STORAGE_KEY = 'ISA_APP_INITIALSTATE';

  constructor(private readonly _userStateService: UserStateService, private _logger: Logger, private _store: Store) {
    if (!environment.production) {
      console.log('Die UserState kann in der Konsole mit der Funktion "clearUserState()" geleert werden.');

      window['clearUserState'] = () => {
        this.clear();
      };
    }
  }

  async init() {
    await this.load();
    this._store.dispatch({ type: 'HYDRATE', payload: RootStateService.LoadFromLocalStorage() });
    this.initSave();
  }

  initSave() {
    this._store
      .select((state) => state)
      .pipe(
        debounceTime(500),
        switchMap((state) => {
          const raw = JSON.stringify({ ...state, version: packageInfo.version });
          RootStateService.SaveToLocalStorageRaw(raw);
          return this._userStateService.UserStateSetUserState({ content: raw });
        })
      )
      .subscribe();
  }

  /**
   * Loads the initial state from local storage and returns true/false if state was changed
   */
  async load(): Promise<boolean> {
    try {
      const res = await this._userStateService.UserStateGetUserState().toPromise();

      const resContent = res?.result?.content ?? null;
      const storageContent = RootStateService.LoadFromLocalStorageRaw();

      if (resContent) {
        RootStateService.SaveToLocalStorageRaw(res.result.content);
      }

      if (resContent !== storageContent) {
        return true;
      }
    } catch (error) {
      this._logger.log(LogLevel.ERROR, error);
    }
    return false;
  }

  clear() {
    this._userStateService
      .UserStateResetUserState()
      .toPromise()
      .catch((error) => this._logger.log(LogLevel.ERROR, error));
    RootStateService.RemoveFromLocalStorage();
    window.location.reload();
  }

  static SaveToLocalStorage(state: RootState) {
    RootStateService.SaveToLocalStorageRaw(JSON.stringify(state));
  }

  static SaveToLocalStorageRaw(state: string) {
    localStorage.setItem(RootStateService.LOCAL_STORAGE_KEY, state);
  }

  static LoadFromLocalStorage(): RootState {
    const raw = RootStateService.LoadFromLocalStorageRaw();
    if (raw) {
      return JSON.parse(raw);
    }
    return undefined;
  }

  static LoadFromLocalStorageRaw(): string {
    return localStorage.getItem(RootStateService.LOCAL_STORAGE_KEY);
  }

  static RemoveFromLocalStorage() {
    localStorage.removeItem(RootStateService.LOCAL_STORAGE_KEY);
  }
}
