import { coerceStringArray } from '@angular/cdk/coercion';
import {
  DestroyRef,
  Directive,
  ElementRef,
  EventEmitter,
  Input,
  OnInit,
  Output,
  Renderer2,
  inject,
} from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { NavigationEnd, Router } from '@angular/router';
import { ComponentStore } from '@ngrx/component-store';
import { filter, switchMap } from 'rxjs/operators';

export interface SharedRouterLinkActiveDirectiveState {
  classList: string[];
  test: RegExp | undefined;
}

@Directive({ selector: '[sharedRegexRouterLinkActive]', standalone: true })
export class RegexRouterLinkActiveDirective
  extends ComponentStore<SharedRouterLinkActiveDirectiveState>
  implements OnInit
{
  destroyRef = inject(DestroyRef);

  router = inject(Router);

  elementRef = inject(ElementRef);

  renderer = inject(Renderer2);

  @Input('sharedRegexRouterLinkActive')
  set classList(value: string[] | string) {
    this.patchState({ classList: coerceStringArray(value) });
  }
  get classList() {
    return this.get((s) => s.classList);
  }

  @Input('sharedRegexRouterLinkActiveTest')
  set test(value: RegExp | string) {
    const test = typeof value === 'string' ? new RegExp(value) : value;

    this.patchState({ test });
  }
  get test() {
    return this.get((s) => s.test);
  }

  @Output()
  isActiveChange = new EventEmitter<boolean>();

  constructor() {
    super({
      classList: [],
      test: undefined,
    });
  }

  ngOnInit() {
    this.router.events
      .pipe(
        takeUntilDestroyed(this.destroyRef),
        filter((event) => event instanceof NavigationEnd),
        switchMap(() => this.select((s) => s)),
      )
      .subscribe(() => this.checkActiveLink());

    this.checkActiveLink();
  }

  checkActiveLink() {
    const { classList, test } = this.get((s) => s);

    let isActive = test?.test(this.router.url) ?? false;

    this.isActiveChange.emit(isActive);

    classList.forEach((className) => {
      if (isActive) {
        this.renderer.addClass(this.elementRef.nativeElement, className);
      } else {
        this.renderer.removeClass(this.elementRef.nativeElement, className);
      }
    });
  }
}
