import { Component, ChangeDetectionStrategy, OnInit, OnDestroy, ElementRef } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { ApplicationService } from '@core/application';
import { DomainPrinterService } from '@domain/printer';
import { PrintModalComponent, PrintModalData } from '@modal/printer';
import { AvailabilityDTO, BranchDTO } from '@swagger/checkout';
import { UiModalService } from '@ui/modal';
import { ModalReviewsComponent } from '@modal/reviews';
import { PurchasingOptionsModalComponent, PurchasingOptionsModalData } from 'apps/page/checkout/src/lib/modals/purchasing-options-modal';
import { PurchasingOptions } from 'apps/page/checkout/src/lib/modals/purchasing-options-modal/purchasing-options-modal.store';
import { combineLatest, Subscription } from 'rxjs';
import { filter, first, map, shareReplay } from 'rxjs/operators';
import { ArticleDetailsStore } from './article-details.store';
import { ModalImagesComponent } from 'apps/modal/images/src/public-api';
import { ProductImageService } from 'apps/cdn/product-image/src/public-api';
import { ModalAvailabilitiesComponent } from '@modal/availabilities';
import { slideYAnimation } from './slide.animation';
import { BreadcrumbService } from '@core/breadcrumb';
import { ItemDTO } from '@swagger/cat';
import { DateAdapter } from '@ui/common';
import { DatePipe } from '@angular/common';

@Component({
  selector: 'page-article-details',
  templateUrl: 'article-details.component.html',
  styleUrls: ['article-details.component.scss'],
  changeDetection: ChangeDetectionStrategy.Default,
  providers: [ArticleDetailsStore, DatePipe],
  animations: [slideYAnimation],
})
export class ArticleDetailsComponent implements OnInit, OnDestroy {
  private readonly subscriptions = new Subscription();
  showRecommendations: boolean;

  fetchingAvailabilities$ = combineLatest([
    this.store.fetchingDeliveryAvailability$,
    this.store.fetchingDeliveryB2BAvailability$,
    this.store.fetchingDeliveryDigAvailability$,
    this.store.fetchingDownloadAvailability$,
    this.store.fetchingPickUpAvailability$,
    this.store.fetchingTakeAwayAvailability$,
  ]).pipe(map((values) => values.some((v) => v)));

  isAvailable$ = combineLatest([
    this.store.isDeliveryAvailabilityAvailable$,
    this.store.isDeliveryDigAvailabilityAvailable$,
    this.store.isDeliveryB2BAvailabilityAvailable$,
    this.store.isPickUpAvailabilityAvailable$,
    this.store.isTakeAwayAvailabilityAvailable$,
    this.store.isDownloadAvailabilityAvailable$,
  ]).pipe(
    map((values) => values.some((v) => v)),
    shareReplay()
  );

  showDeliveryTruck$ = combineLatest([this.store.isDeliveryAvailabilityAvailable$, this.store.isDeliveryDigAvailabilityAvailable$]).pipe(
    map(([delivery, digDelivery]) => delivery || digDelivery)
  );

  showDeliveryB2BTruck$ = combineLatest([
    this.store.isDeliveryDigAvailabilityAvailable$,
    this.store.isDeliveryB2BAvailabilityAvailable$,
  ]).pipe(map(([digDelivery, b2bDelivery]) => b2bDelivery && !digDelivery));

  showSubscriptionBadge$ = this.store.item$.pipe(map((item) => item?.features?.find((i) => i.key === 'PFO')));

  showPromotionBadge$ = this.store.item$.pipe(map((item) => item?.features?.find((i) => i.key === 'Promotion')));

  showArchivBadge$ = this.store.item$.pipe(map((item) => item?.features?.find((i) => i.key === 'ARC')));

  isBadgeVisible$ = combineLatest([this.showSubscriptionBadge$, this.showPromotionBadge$, this.showArchivBadge$]).pipe(
    map(([showSubscriptionBadge, showPromotionBadge, showArchivBadge]) => showSubscriptionBadge || showPromotionBadge || showArchivBadge)
  );

  contributors$ = this.store.item$.pipe(map((item) => item?.product?.contributors?.split(';').map((m) => m.trim())));

  publicationDate$ = this.store.item$.pipe(
    filter((item) => !!item?.product?.publicationDate),
    map((item) => {
      const date = this._dateAdapter.parseDate(item.product.publicationDate);

      if (this._dateAdapter.getDate(date) === 1 && this._dateAdapter.getMonth(date) === 0) {
        return this._datePipe.transform(date, 'y');
      }

      return this._datePipe.transform(date, 'dd. MMMM y');
    })
  );

  constructor(
    public readonly applicationService: ApplicationService,
    private activatedRoute: ActivatedRoute,
    public readonly store: ArticleDetailsStore,
    private domainPrinterService: DomainPrinterService,
    private uiModal: UiModalService,
    private productImageService: ProductImageService,
    private breadcrumb: BreadcrumbService,
    private _dateAdapter: DateAdapter,
    private _datePipe: DatePipe,
    public elementRef: ElementRef
  ) {}

  ngOnInit() {
    const id$ = this.activatedRoute.params.pipe(
      map((params) => Number(params?.id) || undefined),
      filter((f) => !!f)
    );

    const ean$ = this.activatedRoute.params.pipe(
      map((params) => params?.ean || undefined),
      filter((f) => !!f)
    );

    this.subscriptions.add(this.store.loadItemById(id$));
    this.subscriptions.add(this.store.loadItemByEan(ean$));
    this.subscriptions.add(this.store.item$.pipe(filter((item) => !!item)).subscribe((item) => this.updateBreadcrumb(item)));
  }

  ngOnDestroy() {
    this.subscriptions.unsubscribe();
  }

  async updateBreadcrumb(item: ItemDTO) {
    const crumbs = await this.breadcrumb
      .getBreadcrumbsByKeyAndTags$(this.applicationService.activatedProcessId, ['catalog', 'details', `${item.id}`])
      .pipe(first())
      .toPromise();

    for (const crumb of crumbs) {
      await this.breadcrumb.removeBreadcrumbsAfter(crumb.id);
    }

    this.breadcrumb.addBreadcrumbIfNotExists({
      key: this.applicationService.activatedProcessId,
      name: item.product?.name,
      path: `/kunde/${this.applicationService.activatedProcessId}/product/details/${item.id}`,
      params: this.activatedRoute.snapshot.queryParams,
      tags: ['catalog', 'details', `${item.id}`],
      section: 'customer',
    });
  }

  async print() {
    const item = await this.store.item$.pipe(first()).toPromise();
    this.uiModal.open({
      content: PrintModalComponent,
      data: {
        printerType: 'Label',
        print: (printer) => this.domainPrinterService.printProduct({ item, printer }).toPromise(),
      } as PrintModalData,
      config: {
        panelClass: [],
        showScrollbarY: false,
      },
    });
  }

  async showReviews() {
    const item = await this.store.item$.pipe(first()).toPromise();

    this.uiModal.open({
      content: ModalReviewsComponent,
      title: `${item.reviews?.length} Rezensionen`,
      data: item.reviews,
    });
  }

  async showAvailabilities() {
    const item = await this.store.item$.pipe(first()).toPromise();
    const modal = this.uiModal.open<BranchDTO>({
      content: ModalAvailabilitiesComponent,
      title: 'Weitere Verfügbarkeiten',
      data: {
        item,
      },
    });

    this.subscriptions.add(
      modal.afterClosed$.subscribe((result) => {
        if (result?.data) {
          this.showPurchasingModal(result.data);
        }
      })
    );
  }

  async showImages() {
    const item = await this.store.item$.pipe(first()).toPromise();
    const images = item.images ? [...item.images] : [];

    images.unshift({
      url: this.productImageService.getImageUrl({
        imageId: item.imageId,
        width: 400,
        height: 655,
      }),
      thumbUrl: this.productImageService.getImageUrl({
        imageId: item.imageId,
        width: 43,
        height: 69,
      }),
    });

    this.uiModal.open({
      content: ModalImagesComponent,
      title: item.product.name,
      data: {
        images,
      },
    });
  }

  async showPurchasingModal(selectedBranch?: BranchDTO) {
    let availableOptions: PurchasingOptions[] = [];
    const availabilities: { [key: string]: AvailabilityDTO } = {};

    const takeNow = await this.store.isTakeAwayAvailabilityAvailable$.pipe(first()).toPromise();
    if (takeNow) {
      availableOptions.push('take-away');
      availabilities['take-away'] = await this.store.takeAwayAvailability$.pipe(first()).toPromise();
    }

    const download = await this.store.isDownloadAvailabilityAvailable$.pipe(first()).toPromise();
    if (download) {
      availableOptions.push('download');
      availabilities['download'] = await this.store.downloadAvailability$.pipe(first()).toPromise();
    }

    const pickup = await this.store.isPickUpAvailabilityAvailable$.pipe(first()).toPromise();
    if (pickup) {
      availableOptions.push('pick-up');
      availabilities['pick-up'] = await this.store.pickUpAvailability$.pipe(first()).toPromise();
    }

    const digDelivery = await this.store.isDeliveryDigAvailabilityAvailable$.pipe(first()).toPromise();
    if (digDelivery) {
      availableOptions.push('dig-delivery');
      availabilities['dig-delivery'] = await this.store.deliveryDigAvailability$.pipe(first()).toPromise();
    }

    const b2b = await this.store.isDeliveryB2BAvailabilityAvailable$.pipe(first()).toPromise();
    if (b2b) {
      availableOptions.push('b2b-delivery');
      availabilities['b2b-delivery'] = await this.store.deliveryB2BAvailability$.pipe(first()).toPromise();
    }

    if (availableOptions.includes('dig-delivery') && availableOptions.includes('b2b-delivery')) {
      availableOptions.push('delivery');
      availabilities['delivery'] = await this.store.deliveryAvailability$.pipe(first()).toPromise();
      availableOptions = availableOptions.filter((option) => !(option === 'dig-delivery' || option === 'b2b-delivery'));
    }

    const branch = selectedBranch || (await this.store.branch$.pipe(first()).toPromise());
    this.uiModal.open({
      content: PurchasingOptionsModalComponent,
      data: {
        availableOptions,
        option: selectedBranch ? 'take-away' : undefined,
        item: await this.store.item$.pipe(first()).toPromise(),
        branchId: branch?.id,
        processId: this.applicationService.activatedProcessId,
        availabilities,
      } as PurchasingOptionsModalData,
    });
  }

  scrollTop() {
    const element = this.elementRef.nativeElement.closest('.main-wrapper');
    element?.scrollTo({ top: 0, behavior: 'smooth' });
  }
}
