import {
  ChangeDetectionStrategy,
  Component,
  OnDestroy,
  OnInit,
  ViewChild,
  inject,
  linkedSignal,
} from '@angular/core';
import { Router } from '@angular/router';
import { BreadcrumbService } from '@core/breadcrumb';
import {
  KeyValueDTOOfStringAndString,
  OrderItemListItemDTO,
} from '@generated/swagger/oms-api';
import { UiErrorModalComponent, UiModalService } from '@ui/modal';
import { UiScrollContainerComponent } from '@ui/scroll-container';
import { BehaviorSubject, combineLatest, Subject } from 'rxjs';
import { first, map, shareReplay, takeUntil } from 'rxjs/operators';
import { GoodsInRemissionPreviewStore } from './goods-in-remission-preview.store';
import { Config } from '@core/config';
import { ToasterService } from '@shared/shell';
import { PickupShelfInNavigationService } from '@shared/services/navigation';
import { CacheService } from '@core/cache';
import { TabService } from '@isa/core/tabs';

@Component({
  selector: 'page-goods-in-remission-preview',
  templateUrl: 'goods-in-remission-preview.component.html',
  styleUrls: ['goods-in-remission-preview.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush,
  providers: [GoodsInRemissionPreviewStore],
  standalone: false,
})
export class GoodsInRemissionPreviewComponent implements OnInit, OnDestroy {
  tabService = inject(TabService);
  private _pickupShelfInNavigationService = inject(
    PickupShelfInNavigationService,
  );
  @ViewChild(UiScrollContainerComponent)
  scrollContainer: UiScrollContainerComponent;

  items$ = this._store.results$;

  itemLength$ = this.items$.pipe(map((items) => items?.length));

  hits$ = this._store.hits$;

  loading$ = this._store.fetching$.pipe(shareReplay());

  changeActionLoader$ = new BehaviorSubject<boolean>(false);

  listEmpty$ = combineLatest([this.loading$, this.hits$]).pipe(
    map(([loading, hits]) => !loading && hits === 0),
    shareReplay(),
  );

  actions$ = this.items$.pipe(map((items) => items[0]?.actions));

  private _onDestroy$ = new Subject<void>();

  byBuyerNumberFn = (item: OrderItemListItemDTO) => item.buyerNumber;

  byOrderNumberFn = (item: OrderItemListItemDTO) => item.orderNumber;

  byProcessingStatusFn = (item: OrderItemListItemDTO) => item.processingStatus;

  byCompartmentCodeFn = (item: OrderItemListItemDTO) =>
    item.compartmentInfo
      ? `${item.compartmentCode}_${item.compartmentInfo}`
      : item.compartmentCode;

  private readonly SCROLL_POSITION_TOKEN = 'REMISSION_PREVIEW_SCROLL_POSITION';

  remissionPath = linkedSignal(() => [
    '/',
    this.tabService.activatedTab()?.id || Date.now(),
    'remission',
  ]);

  constructor(
    private _breadcrumb: BreadcrumbService,
    private _store: GoodsInRemissionPreviewStore,
    private _router: Router,
    private _modal: UiModalService,
    private _config: Config,
    private _toast: ToasterService,
    private _cache: CacheService,
  ) {}

  ngOnInit(): void {
    this.initInitialSearch();
    this.createBreadcrumb();
    this.removeBreadcrumbs();
  }

  ngOnDestroy(): void {
    this._onDestroy$.next();
    this._onDestroy$.complete();
    this._addScrollPositionToCache();
    this.updateBreadcrumb();
  }

  private _removeScrollPositionFromCache(): void {
    this._cache.delete({
      processId: this._config.get('process.ids.goodsIn'),
      token: this.SCROLL_POSITION_TOKEN,
    });
  }

  private _addScrollPositionToCache(): void {
    this._cache.set<number>(
      {
        processId: this._config.get('process.ids.goodsIn'),
        token: this.SCROLL_POSITION_TOKEN,
      },
      this.scrollContainer?.scrollPos,
    );
  }

  private async _getScrollPositionFromCache(): Promise<number> {
    return await this._cache.get<number>({
      processId: this._config.get('process.ids.goodsIn'),
      token: this.SCROLL_POSITION_TOKEN,
    });
  }

  async createBreadcrumb() {
    await this._breadcrumb.addOrUpdateBreadcrumbIfNotExists({
      key: this._config.get('process.ids.goodsIn'),
      name: 'Abholfachremissionsvorschau',
      path: '/filiale/goods/in/preview',
      section: 'branch',
      params: { view: 'remission' },
      tags: ['goods-in', 'preview'],
    });
  }

  async updateBreadcrumb() {
    const crumbs = await this._breadcrumb
      .getBreadcrumbsByKeyAndTags$(this._config.get('process.ids.goodsIn'), [
        'goods-in',
        'preview',
      ])
      .pipe(first())
      .toPromise();
    for (const crumb of crumbs) {
      this._breadcrumb.patchBreadcrumb(crumb.id, {
        name: crumb.name,
      });
    }
  }

  async removeBreadcrumbs() {
    let breadcrumbsToDelete = await this._breadcrumb
      .getBreadcrumbsByKeyAndTags$(this._config.get('process.ids.goodsIn'), [
        'goods-in',
      ])
      .pipe(first())
      .toPromise();

    breadcrumbsToDelete = breadcrumbsToDelete.filter(
      (crumb) =>
        !crumb.tags.includes('preview') && !crumb.tags.includes('main'),
    );

    breadcrumbsToDelete.forEach((crumb) => {
      this._breadcrumb.removeBreadcrumb(crumb.id, true);
    });

    const detailsCrumbs = await this._breadcrumb
      .getBreadcrumbsByKeyAndTags$(this._config.get('process.ids.goodsIn'), [
        'goods-in',
        'details',
      ])
      .pipe(first())
      .toPromise();
    const editCrumbs = await this._breadcrumb
      .getBreadcrumbsByKeyAndTags$(this._config.get('process.ids.goodsIn'), [
        'goods-in',
        'edit',
      ])
      .pipe(first())
      .toPromise();

    detailsCrumbs.forEach((crumb) => {
      this._breadcrumb.removeBreadcrumb(crumb.id, true);
    });

    editCrumbs.forEach((crumb) => {
      this._breadcrumb.removeBreadcrumb(crumb.id, true);
    });
  }

  initInitialSearch() {
    if (this._store.hits === 0) {
      this._store.searchResult$
        .pipe(takeUntil(this._onDestroy$))
        .subscribe(async (result) => {
          await this.createBreadcrumb();

          this.scrollContainer?.scrollTo(
            (await this._getScrollPositionFromCache()) ?? 0,
          );
          this._removeScrollPositionFromCache();
        });
    }

    this._store.search();
  }

  async navigateToRemission() {
    await this._router.navigate(this.remissionPath());
  }

  navigateToDetails(orderItem: OrderItemListItemDTO) {
    const nav = this._pickupShelfInNavigationService.detailRoute({
      item: orderItem,
      side: false,
    });

    this._router.navigate(nav.path, {
      queryParams: { ...nav.queryParams, view: 'remission' },
    });
  }

  async handleAction(action: KeyValueDTOOfStringAndString) {
    this.changeActionLoader$.next(true);

    try {
      const response = await this._store
        .createRemissionFromPreview()
        .pipe(first())
        .toPromise();

      if (!response?.dialog) {
        this._toast.open({
          title: 'Abholfachremission',
          message: response?.message,
        });
      }

      await this.navigateToRemission();
    } catch (error) {
      this._modal.open({
        content: UiErrorModalComponent,
        data: error,
      });
      console.error(error);
    }

    this.changeActionLoader$.next(false);
  }
}
