import {Directive, OnDestroy} from "@angular/core";
import {BehaviorSubject, Subscriber} from "rxjs";
import {EnvProperties} from "../../utils/properties/env-properties";
import {properties} from "src/environments/environment";
import {PiwikService} from "../../utils/piwik/piwik.service";
import {Meta, Title} from "@angular/platform-browser";
import {SEOService} from "../SEO/SEO.service";
import {ActivatedRoute, Data, NavigationEnd, Params, Router} from "@angular/router";
import {StringUtils} from "../../utils/string-utils.class";
import {RouterHelper} from "../../utils/routerHelper.class";

@Directive()
export abstract class BaseComponent implements OnDestroy {
  public properties: EnvProperties = properties;
  /** Router params */
  protected paramsResolved: boolean = false;
  protected params: BehaviorSubject<Params>;
  protected data: BehaviorSubject<Data>;
  protected subscriptions: any[] = [];
  /** Metadata */
  public title: string;
  public description: string;
  public url: string;
  protected _route: ActivatedRoute;
  protected _piwikService: PiwikService;
  protected _meta: Meta;
  protected seoService: SEOService;
  protected _title: Title;
  protected _router: Router;
  public routerHelper: RouterHelper = new RouterHelper();

  protected constructor() {
  }

  ngOnDestroy() {
    this.subscriptions.forEach(subscription => {
      if (subscription instanceof Subscriber) {
        subscription.unsubscribe()
      } else if (subscription instanceof Function) {
        subscription();
      } else if (typeof IntersectionObserver !== 'undefined' && subscription instanceof IntersectionObserver) {
        subscription.disconnect();
      } else if (typeof ResizeObserver !== 'undefined' && subscription instanceof ResizeObserver) {
        subscription.disconnect();
      }
    });
  }

  /**
   * Initialize router params and data (should be called in the constructor of a component with router-outlet)
   * */
  initRouterParams(route: ActivatedRoute = null, navigationChange: ((event: NavigationEnd) => void) = null) {
    if (route) {
      this.params = new BehaviorSubject<Params>(null);
      this.data = new BehaviorSubject<Data>(null);
      this.subscriptions.push(this._router.events.subscribe(event => {
        if (event instanceof NavigationEnd) {
          if(navigationChange) {
            navigationChange(event);
          }
          let r = route;
          while (r.firstChild) {
            r = r.firstChild;
          }
          let data = r.snapshot.data;
          let params = r.snapshot.params;
          let current = r.snapshot;
          while (current.parent) {
            data = {...current.parent.data, ...data};
            params = {...current.parent.params, ...params};
            current = current.parent;
          }
          r.snapshot.data = data;
          r.snapshot.params = params;
          this.paramsResolved = true;
          this.params.next(r.snapshot.params);
          this.data.next(r.snapshot.data);
        }
      }));
    }
  }

  public setMetadata() {
    if (this._title && this.title) {
      this.title = (this._route?.snapshot.data?.title ? this._route.snapshot.data?.title : '') + this.title;
      this._title.setTitle(this.title);
    }
    if (this._router) {
      this.url = properties.domain + properties.baseLink + this._router.url;
      if (this.seoService) {
        this.seoService.createLinkForCanonicalURL(this.url, false);
      }
      if (this._meta) {
        this._meta.updateTag({content: this.url}, "property='og:url'");
        this._meta.updateTag({content: this.description}, "name='description'");
        this._meta.updateTag({content: this.description}, "property='og:description'");
        this._meta.updateTag({content: this.title}, "property='og:title'");
      }
    }
    this.trackView();
  }

  public trackView() {
    if (this._piwikService) {
      this.subscriptions.push(this._piwikService.trackView(properties, this.title).subscribe());
    }
  }

  public quote(str: string) {
    return StringUtils.quote(str);
  }
}
