import {
  AfterViewInit,
  ChangeDetectionStrategy,
  Component,
  ElementRef,
  Input,
  QueryList,
  ViewChildren,
} from '@angular/core';
import { Breadcrumb, BreadcrumbService } from '@core/breadcrumb';
import { ComponentStore } from '@ngrx/component-store';
import { isEqual } from 'lodash';
import { combineLatest, Observable } from 'rxjs';
import { debounceTime, map, switchMap, tap } from 'rxjs/operators';
import { BreadcrumbComponentState, DEFAULT_BREADCRUMB_COMPONENT_STATE } from './breadcrumb.component-state';
import { coerceArray } from '@angular/cdk/coercion';

@Component({
  selector: 'shared-breadcrumb',
  templateUrl: './breadcrumb.component.html',
  styleUrls: ['./breadcrumb.component.css'],
  changeDetection: ChangeDetectionStrategy.OnPush,
  host: {
    class: 'shared-breadcrumb mb-5 desktop-small:mb-9',
  },
  standalone: false,
})
export class BreadcrumbComponent extends ComponentStore<BreadcrumbComponentState> implements AfterViewInit {
  @ViewChildren('breadcrumb') breadcrumbElements: QueryList<ElementRef>;

  /**
   * Eindeutiger Schlüssel, der die Breadcrumb-Liste identifiziert.
   */
  @Input()
  get key(): string | number {
    return this.get((s) => s.key);
  }

  set key(key: string | number) {
    if (this.key === key) return;
    this.patchState({ key });
  }

  readonly key$: Observable<string | number> = this.select((s) => s.key);

  /**
   * Tags, die die Breadcrumb enthalten soll.
   * Hier können auch nut Teile der Tags angeben werden  die in der Breadcrumb enthalten sein sollen.
   */
  @Input()
  get tags(): string[] | string {
    return this.get((s) => s.tags);
  }

  set tags(tags: string[] | string) {
    const tagsArray = coerceArray(tags);
    if (isEqual(this.tags, tagsArray)) return;
    this.patchState({ tags: tagsArray });
  }

  readonly tags$: Observable<string[]> = this.select((s) => s.tags);

  /**
   * Breadcrumb-Liste, die anhand des Schlüssels und der Tags ermittelt wird.
   */
  readonly breadcrumbs$: Observable<Breadcrumb[]> = combineLatest([this.key$, this.tags$]).pipe(
    switchMap(([key, tags]) => this._breadcrumbService.getBreadcrumbsByKeyAndTags$(key, tags)),
  );

  /**
   * Vorgänger-Breadcrumb, die anhand der Breadcrumb-Liste ermittelt wird.
   */
  readonly previousBreadcrumb$: Observable<Breadcrumb | undefined> = this.breadcrumbs$.pipe(
    map((crumbs) => crumbs[crumbs.length - 2]),
  );

  constructor(private _breadcrumbService: BreadcrumbService) {
    super(DEFAULT_BREADCRUMB_COMPONENT_STATE);
  }

  ngAfterViewInit(): void {
    this.breadcrumbElements.changes.pipe(debounceTime(100)).subscribe((elements) => {
      this.breadcrumbElements.last.nativeElement.scrollIntoView();
    });
  }
}
