import { 
  Directive, 
  OnDestroy,
  OnInit,
  TemplateRef,
  ViewContainerRef } from '@angular/core';
import { MsalBroadcastService, MsalService } from '@azure/msal-angular';
import { InteractionStatus } from '@azure/msal-browser';
import { 
  filter,
  Subject,
  Subscription,
  takeUntil } from 'rxjs';

@Directive({
  selector: '[authorized]'
})
export class AuthorizedDirective implements OnInit, OnDestroy {
  private hasView: boolean = false;
  private readonly _destroying$ = new Subject<void>();
  private broadcastSubscription!: Subscription;
  
  /**
   * Constructor
   * @param templateRef Referentie to the template that contains the HTML element that the directive is placed on
   * @param viewContainer The view container to which the templateRef will be added
   * @param authService Authentication service
   * @param broadcastService Broadcast service to listen for changes in the authentication state
   */
  constructor(
    private templateRef: TemplateRef<any>,
    private viewContainer: ViewContainerRef,
    private authService: MsalService,
    private broadcastService: MsalBroadcastService

  ) {
    this.setDisplay();
  }

   /**
    * Runs when directive is initialized
    */
  public ngOnInit(): void {
    this.broadcastSubscription = this.broadcastService.inProgress$.pipe(
      filter((eventType: InteractionStatus) => eventType === InteractionStatus.None),
      takeUntil(this._destroying$)
    ).subscribe(() => {
      this.setDisplay();
    });
  }

  /**
   * Clearup any subscriptions
   */
  public ngOnDestroy(): void {
    this._destroying$.next(undefined);
    this._destroying$.complete();
    this.broadcastSubscription.unsubscribe();
  }

  /**
   * Sets the display of the element based on the users authentication
   */
  private setDisplay(): void {
    const account = this.authService.instance.getActiveAccount();
    if (account && !this.hasView) {
      this.viewContainer.createEmbeddedView(this.templateRef);
      this.hasView = true;
    } else if (!account && this.hasView) {
      this.viewContainer.clear();
      this.hasView = false;
    }
  }
}