import { ChangeDetectionStrategy, Component, OnInit, ViewChild, OnDestroy } from '@angular/core';
import { Config } from '@core/config';
import { provideComponentStore } from '@ngrx/component-store';
import { SharedFilterOverlayComponent } from '@shared/components/filter-overlay';
import { UiFilter } from '@ui/filter';
import { PriceUpdateComponentStore } from './price-update.component.store';
import { combineLatest, Subject, Subscription } from 'rxjs';
import { filter, first, map } from 'rxjs/operators';
import { ActivatedRoute, Params, Router } from '@angular/router';
import { Breadcrumb, BreadcrumbService } from '@core/breadcrumb';
import { ListResponseArgsOfProductListItemDTO } from '@generated/swagger/wws-api';
import { provideCancelSearchSubject } from '@shared/services/cancel-subject';

@Component({
  selector: 'page-price-update',
  templateUrl: 'price-update.component.html',
  styleUrls: ['price-update.component.css'],
  changeDetection: ChangeDetectionStrategy.OnPush,
  providers: [provideComponentStore(PriceUpdateComponentStore), provideCancelSearchSubject()],
  standalone: false,
})
export class PriceUpdateComponent implements OnInit, OnDestroy {
  private _subscription = new Subscription();

  get breadcrumbKey(): string {
    return this._config.get('process.ids.assortment');
  }

  hint$ = new Subject<string>();

  @ViewChild(SharedFilterOverlayComponent)
  filterOverlay: SharedFilterOverlayComponent;

  /**
   * Zeigt die liste an, wenn entweder keine items geladen werden oder wenn items geladen wurden
   * und mindestens ein item vorhanden ist.
   */
  showList$ = combineLatest([this.store.fetching$, this.store.items$]).pipe(
    map(([fetching, items]) => fetching || items.length > 0),
  );

  constructor(
    public store: PriceUpdateComponentStore,
    private _activatedRoute: ActivatedRoute,
    private _config: Config,
    private _breadcrumb: BreadcrumbService,
    private _router: Router,
  ) {}

  ngOnInit(): void {
    this.initFilterSubscription();

    this.initFetchResponseSubscription();

    this.removeBreadcrumbs();
  }

  initFilterSubscription() {
    const initialFilter$ = this.store.filter$.pipe(
      filter((f) => f instanceof UiFilter),
      first(),
    );
    const queryParams$ = this._activatedRoute.queryParams;

    const filterSub = combineLatest([initialFilter$, queryParams$]).subscribe(([filter, queryParams]) => {
      const restored = this.restoreFilterFromQueryParams(filter, queryParams);
      this.fetchItems(restored);
    });

    this._subscription.add(filterSub);
  }

  initFetchResponseSubscription() {
    const onFetchItemsResponseSub = this.store.onFetchingItemsResponse$.subscribe(this.onFetchingItemsResponse);

    this._subscription.add(onFetchItemsResponseSub);
  }

  ngOnDestroy(): void {
    this._subscription.unsubscribe();
  }

  restoreFilterFromQueryParams(filter: UiFilter, queryParams: Params): UiFilter {
    const nextFilter = UiFilter.create(filter);
    nextFilter.fromQueryParams(queryParams);
    this.store.setFilter(nextFilter);
    this.store.setPendingFilter(nextFilter);
    return nextFilter;
  }

  applyFilter() {
    this.store.applyPendingFilterToFilter();
    this.fetchItems(this.store.filter);
  }

  fetchItems(filter: UiFilter) {
    this.hint$.next('');
    this.store.fetchItems();
    this.patchLocation(filter);
  }

  onFetchingItemsResponse = (response: ListResponseArgsOfProductListItemDTO) => {
    this.createBreadcrumbIfNotExists(this.store.filter);
    if (response.error) {
      console.error(response);
      return;
    }

    if (response.result.length === 0 && this.filterOverlay.isOpen) {
      this.hint$.next('Keine Preisänderungen vorhanden');
      return;
    }

    this.filterOverlay.close();
  };

  async patchLocation(filter: UiFilter): Promise<void> {
    this._router.navigate([], {
      queryParams: filter.getQueryParams(),
    });
  }

  async createBreadcrumbIfNotExists(filter: UiFilter): Promise<void> {
    const crumb: Breadcrumb = {
      key: this.breadcrumbKey,
      name: 'Preisänderung',
      path: '/filiale/assortment/price-update',
      section: 'branch',
      params: filter.getQueryParams(),
      tags: ['filter'],
    };

    await this._breadcrumb.addOrUpdateBreadcrumbIfNotExists(crumb);
  }

  async removeBreadcrumbs(): Promise<void> {
    const filterCrumbs = await this._breadcrumb
      .getBreadcrumbsByKeyAndTag$(this.breadcrumbKey, 'filter')
      .pipe(first())
      .toPromise();
    const crumbs = [...filterCrumbs];
    for (let crumb of crumbs) {
      await this._breadcrumb.removeBreadcrumb(crumb.id);
    }
  }

  closeFilterOverlay() {
    this.hint$.next('');
    this.store.restorePendingFilter();
    this.filterOverlay.close();
  }
}
