import { Pipe, PipeTransform, OnDestroy, ChangeDetectorRef } from '@angular/core';
import { Subscription, Subject, combineLatest, timer } from 'rxjs';

import { map } from 'rxjs/operators';
import { TimeWindow } from '../defs';
import { DateAdapter } from '../components/calendar/providers';

@Pipe({
  name: 'inTimeWindow',
  pure: false,
})
export class InTimeWindowPipe implements PipeTransform, OnDestroy {
  private value$ = new Subject<TimeWindow>();
  private value: TimeWindow;
  private returnValue: boolean;

  private clock = new Subject<Date>();
  private clockIntervall: number;

  private valueSubscription: Subscription;
  private clockSubscription: Subscription;

  constructor(private ref: ChangeDetectorRef, private dateAdapter: DateAdapter) {
    // tslint:disable-next-line: deprecation
    this.valueSubscription = combineLatest(this.value$, this.clock).subscribe(([timeWindow, clockTime]) => {
      const clockTimeDate = this.dateAdapter.getDate(clockTime);

      const from = this.dateAdapter.parseDate(clockTimeDate.year, clockTimeDate.month, clockTimeDate.date);
      from.setHours(timeWindow.from.hours);
      from.setMinutes(timeWindow.from.minutes);

      const to = this.dateAdapter.parseDate(clockTimeDate.year, clockTimeDate.month, clockTimeDate.date);
      to.setHours(timeWindow.to.hours);
      to.setMinutes(timeWindow.to.minutes + 1);

      const nextReturnValue = from <= clockTime && clockTime < to;

      if (this.returnValue !== nextReturnValue) {
        this.returnValue = nextReturnValue;
        this.ref.markForCheck();
      }
    });
  }

  setClockIntervall(intervall: number) {
    if (this.clockIntervall === intervall) {
      return;
    }

    if (!!this.clockSubscription) {
      this.clockSubscription.unsubscribe();
    }

    this.clockIntervall = intervall;

    this.clock.next(new Date());

    const now = Date.now();

    this.clockSubscription = timer(new Date(now + (now % intervall) + intervall), intervall)
      .pipe(map((_) => new Date()))
      .subscribe(this.clock);
  }

  transform(value: TimeWindow, intervall: number = 10000): any {
    this.setClockIntervall(intervall);

    if (!this.equals(value, this.value)) {
      this.value = value;
      this.value$.next(value);
    }

    return this.returnValue;
  }

  ngOnDestroy() {
    if (!!this.valueSubscription) {
      this.valueSubscription.unsubscribe();
      delete this.valueSubscription;
    }
    if (!!this.clockSubscription) {
      this.clockSubscription.unsubscribe();
      delete this.clockSubscription;
    }
  }

  equals(tw1: TimeWindow, tw2: TimeWindow) {
    if (!!tw1 && !!tw2) {
      if (tw1 === tw2) {
        return true;
      }

      if (!!tw1.from && !!tw2.from) {
        if (tw1.from.hours !== tw2.from.hours) {
          return false;
        }

        if (tw1.from.minutes !== tw2.from.minutes) {
          return false;
        }
      }

      if (!!tw1.to && !!tw2.to) {
        if (tw1.to.hours !== tw2.to.hours) {
          return false;
        }

        if (tw1.to.minutes !== tw2.to.minutes) {
          return false;
        }
      }

      return true;
    }

    return false;
  }
}
