import { ChangeDetectionStrategy, Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { ApplicationService } from '@core/application';
import { DomainAvailabilityService } from '@domain/availability';
import { DomainCheckoutService } from '@domain/checkout';
import { ComponentStore } from '@ngrx/component-store';
import { ShoppingCartItemDTO } from '@swagger/checkout';
import { combineLatest } from 'rxjs';
import { filter, first, map, shareReplay, switchMap } from 'rxjs/operators';

export interface ShoppingCartItemComponentState {
  item: ShoppingCartItemDTO;
  orderType: string;
  loadingOnItemChangeById?: number;
  loadingOnQuantityChangeById?: number;
}

@Component({
  selector: 'page-shopping-cart-item',
  templateUrl: 'shopping-cart-item.component.html',
  styleUrls: ['shopping-cart-item.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ShoppingCartItemComponent extends ComponentStore<ShoppingCartItemComponentState> implements OnInit {
  @Output() changeItem = new EventEmitter<{ shoppingCartItem: ShoppingCartItemDTO }>();
  @Output() changeDummyItem = new EventEmitter<{ shoppingCartItem: ShoppingCartItemDTO }>();
  @Output() changeQuantity = new EventEmitter<{ shoppingCartItem: ShoppingCartItemDTO; quantity: number }>();

  @Input()
  get item() {
    return this.get((s) => s.item);
  }
  set item(item: ShoppingCartItemDTO) {
    if (this.item !== item) {
      this.patchState({ item });
    }
  }
  readonly item$ = this.select((s) => s.item);

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

  @Input()
  get orderType() {
    return this.get((s) => s.orderType);
  }
  set orderType(orderType: string) {
    if (this.orderType !== orderType) {
      this.patchState({ orderType });
    }
  }
  readonly orderType$ = this.select((s) => s.orderType);

  @Input()
  get loadingOnItemChangeById() {
    return this.get((s) => s.loadingOnItemChangeById);
  }
  set loadingOnItemChangeById(loadingOnItemChangeById: number) {
    if (this.loadingOnItemChangeById !== loadingOnItemChangeById) {
      this.patchState({ loadingOnItemChangeById });
    }
  }
  readonly loadingOnItemChangeById$ = this.select((s) => s.loadingOnItemChangeById).pipe(shareReplay());

  @Input()
  get loadingOnQuantityChangeById() {
    return this.get((s) => s.loadingOnQuantityChangeById);
  }
  set loadingOnQuantityChangeById(loadingOnQuantityChangeById: number) {
    if (this.loadingOnQuantityChangeById !== loadingOnQuantityChangeById) {
      this.patchState({ loadingOnQuantityChangeById });
    }
  }
  readonly loadingOnQuantityChangeById$ = this.select((s) => s.loadingOnQuantityChangeById).pipe(shareReplay());

  @Input()
  quantityError: string;

  isDummy$ = this.item$.pipe(
    map((item) => item?.availability?.supplyChannel === 'MANUALLY'),
    shareReplay()
  );
  hasOrderType$ = this.orderType$.pipe(
    map((orderType) => orderType !== undefined),
    shareReplay()
  );

  quantityRange$ = combineLatest([this.orderType$, this.item$]).pipe(
    map(([orderType, item]) => (orderType === 'Rücklage' ? item.availability?.inStock : 999))
  );

  isDownloadAvailable$ = combineLatest([this.item$, this.orderType$]).pipe(
    filter(([_, orderType]) => orderType === 'Download'),
    switchMap(([item]) =>
      this.availabilityService.getDownloadAvailability({
        item: { ean: item.product.ean, price: item.availability.price, itemId: +item.product.catalogProductNumber },
      })
    ),
    map((availability) => availability && this.availabilityService.isAvailable({ availability }))
  );

  olaError$ = this.checkoutService
    .getOlaErrors({ processId: this.application.activatedProcessId })
    .pipe(map((ids) => ids?.find((id) => id === this.item.id)));

  constructor(
    private availabilityService: DomainAvailabilityService,
    private checkoutService: DomainCheckoutService,
    public application: ApplicationService
  ) {
    super({ item: undefined, orderType: '' });
  }

  ngOnInit() {}

  async onChangeItem() {
    const isDummy = await this.isDummy$.pipe(first()).toPromise();
    isDummy ? this.changeDummyItem.emit({ shoppingCartItem: this.item }) : this.changeItem.emit({ shoppingCartItem: this.item });
  }

  onChangeQuantity(quantity: number) {
    this.changeQuantity.emit({ shoppingCartItem: this.item, quantity });
  }
}
