import {take, takeUntil} from "rxjs/operators";
import {OnDestroy, OnInit} from "@angular/core";
import {Observable, Subject} from "rxjs";
import {ActivatedRoute, Router} from "@angular/router";
import {UrlUtils} from "../utils/url.utils";

export abstract class SubscribingComponent implements OnInit, OnDestroy {
  protected subscribers$ = []
  protected destroy$ = new Subject<boolean>()
  unknownError = false

  protected constructor(
    protected activatedRoute: ActivatedRoute,
    protected router: Router,
    protected urlUtils = new UrlUtils(activatedRoute, router)
  ) {
  }

  subscribe<T>(observable: Observable<T>, observer, take_count = -1) {
    if (!observer.error) {
      observer.error = err => this.handleObserverError(err)
    }

    if (take_count >= 0) {
      observable.pipe(take(take_count), takeUntil(this.destroy$))
    } else {
      observable.pipe(takeUntil(this.destroy$))
    }
    this.subscribers$.push(observable.subscribe(observer))
  }

  subscribeAndNavigate(observable: Observable<any>, route: string) {
    this.subscribe(
      observable,
      {
        next: () => this.urlUtils.navigateTo(route)
      },
      1
    )
  }

  subscribeEntityByIdFromRoute<T>(service: any, entitySubject: Subject<T>, notFoundRoute: string, paramName: string = 'id') {
    const id = this.urlUtils.parseIntUrlParam(paramName)
    this.subscribe(
      service.getById(id),
      {
        next: e => entitySubject.next(e),
        error: err => {
          if (err.status === 404) {
            this.urlUtils.navigateTo(notFoundRoute)
          } else {
            this.handleObserverError(err)
          }
        }
      },
      1
    )
  }

  ngOnInit(): void {
  }

  ngOnDestroy(): void {
    this.destroy$.next(true)
    this.destroy$.complete()
  }

  handleObserverError(error: any) {
    console.error(error)
    this.unknownError = true
  }

  handleNotFoundError(error: any, route: string) {
    if (error.status === 404) {
      this.urlUtils.navigateTo(route)
    } else {
      this.handleObserverError(error)
    }
  }
}
