import {
  ChangeDetectorRef,
  Injectable,
  OnDestroy,
  Pipe,
  PipeTransform
} from '@angular/core';
import { Subscription } from 'rxjs';
import { ObjectUtil } from '@ucap-webmessenger/core';
import {
  TranslateService,
  LangChangeEvent
} from '../services/translate.service';

@Injectable()
@Pipe({
  name: 'ucapTranslate',
  pure: false // required to update the value when the promise is resolved
})
export class TranslatePipe implements PipeTransform, OnDestroy {
  value = '';
  lastTarget: any;
  lastKey: string;
  lastSeparator: string;
  changedLangSubscription: Subscription;
  changedDefaultLangSubscription: Subscription;

  constructor(
    private translateService: TranslateService,
    private changeDetectorRef: ChangeDetectorRef
  ) {}

  updateValue(target: any, key: string, separator?: string): void {
    try {
      const value = this.translateService.get(target, key, separator);
      this.value = value;
    } catch (error) {
      this.value = key;
    }
    this.lastTarget = target;
    this.lastKey = key;
    this.changeDetectorRef.markForCheck();
  }

  transform(target: any, key: string, separator?: string): any {
    if (
      !target ||
      0 === Object.keys(target).length ||
      !key ||
      0 === key.length
    ) {
      return '';
    }

    // if we ask another time for the same key, return the last value
    if (
      ObjectUtil.equals(target, this.lastTarget) &&
      ObjectUtil.equals(key, this.lastKey) &&
      ObjectUtil.equals(separator, this.lastSeparator)
    ) {
      return this.value;
    }

    // store the target, in case it changes
    this.lastTarget = target;
    // store the key, in case it changes
    this.lastKey = key;
    // store the key, in case it changes
    this.lastSeparator = separator;

    // set the value
    this.updateValue(target, key, separator);

    // if there is a subscription to onLangChange, clean it
    this._dispose();

    // subscribe to onLangChange event, in case the language changes
    if (!this.changedLangSubscription) {
      this.changedLangSubscription = this.translateService.changedLang.subscribe(
        (event: LangChangeEvent) => {
          if (this.lastKey) {
            this.lastKey = null; // we want to make sure it doesn't return the same value until it's been updated
            this.updateValue(target, key, separator);
          }
        }
      );
    }

    // subscribe to onDefaultLangChange event, in case the default language changes
    if (!this.changedDefaultLangSubscription) {
      this.changedDefaultLangSubscription = this.translateService.changedDefaultLang.subscribe(
        () => {
          if (this.lastKey) {
            this.lastKey = null; // we want to make sure it doesn't return the same value until it's been updated
            this.updateValue(target, key, separator);
          }
        }
      );
    }

    return this.value;
  }

  /**
   * Clean any existing subscription to change events
   */
  private _dispose(): void {
    if (!!this.changedLangSubscription) {
      this.changedLangSubscription.unsubscribe();
      this.changedLangSubscription = undefined;
    }
    if (!!this.changedDefaultLangSubscription) {
      this.changedDefaultLangSubscription.unsubscribe();
      this.changedDefaultLangSubscription = undefined;
    }
  }

  ngOnDestroy(): void {
    this._dispose();
  }
}
