import { UpdateCartEntryQuantity } from './../../../../core/store/actions/cart-entry.actions';
import { CartReviewItem } from '../../pages/cart-review/cart-review.component';
import {
  Component,
  OnInit,
  Input,
  ChangeDetectionStrategy,
  Output,
  EventEmitter,
  ChangeDetectorRef,
  ViewChild,
  OnDestroy,
  ViewRef,
} from '@angular/core';
import { ProductAvailabilityService } from '../../../../core/services/product-availability.service';
import { map, tap, take, takeUntil } from 'rxjs/operators';
import { Store } from '@ngxs/store';
import { DeleteProductFromCart } from '../../../../core/store/actions/cart.actions';
import { ChangeOrderTypeComponent } from '../change-order-type/change-order-type.component';
import { Subject, of, Observable } from 'rxjs';

import { DeleteDropdownComponent } from '@libs/ui';
import { allowedAvailabilityStatusCodes } from 'apps/sales/src/app/core/utils/product.util';
import { DeliveryOption } from 'apps/sales/src/app/core/models/delivery-option.model';
import { isNullOrUndefined } from 'util';
import { AvailabilityDTO } from '@swagger/cat';

@Component({
  selector: 'app-pick-up-cart-row',
  templateUrl: './pick-up-cart-row.component.html',
  styleUrls: ['./pick-up-cart-row.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class PickUpCartRowComponent implements OnInit, OnDestroy {
  @ViewChild('changeOrder') changeOrderDialog: ChangeOrderTypeComponent;
  @ViewChild('ref') deleteDropdown: DeleteDropdownComponent;
  @Input() item: CartReviewItem;
  @Output() details = new EventEmitter();
  @Output() editAdress = new EventEmitter();
  @Output() quantity = new EventEmitter();
  @Output() modalVisible = new EventEmitter();
  @Output() delete = new EventEmitter();
  destroy$ = new Subject();
  loadingBtn = false;
  deactivateTenPlus = false;

  get price(): number {
    if (this.item) {
      if (this.item.deliveryType === DeliveryOption.PICK_UP) {
        return this.item.pickUpPrice ? this.item.pickUpPrice : this.item.price;
      } else if (this.item.deliveryType === DeliveryOption.DELIVERY) {
        return this.item.deliveryPrice ? this.item.deliveryPrice : this.item.price;
      } else {
        return this.item.price;
      }
    }
    return 0;
  }

  _open = false;
  get open$() {
    return of(this._open);
  }

  _btnBlocked: boolean;
  @Input() set changeItemBtnBlocked(blockedItemId: number) {
    this._btnBlocked = blockedItemId && blockedItemId !== this.item.cartEntryId ? true : false;
  }

  quantityError;
  availableQuantity = Array(9)
    .fill(0)
    .map((_, i) => i + 1);

  constructor(private availabilityService: ProductAvailabilityService, private store: Store, private cdRef: ChangeDetectorRef) {}

  ngOnInit() {
    if (this.item.orderTypeChanged) {
      this.onQuantityChanged(this.item.quantity, true);
    }

    if (this.item.avaMessage) {
      this.quantityError = this.item.avaMessage;
      const options = this.item.quantity < 9 ? this.item.quantity : 9;

      this.deactivateTenPlus = options < 9;
    }
  }

  async onQuantityChanged(quantity: number, showError: boolean = false) {
    const av = await this.validateSelectedQuantity(quantity).pipe(takeUntil(this.destroy$)).toPromise();

    if (quantity > 999) {
      this.setQuantityError(quantity, 999);
    } else if (quantity < 999 && av) {
      this.setQuantityError(quantity, av.qty);
      this.store.dispatch(new UpdateCartEntryQuantity(quantity, this.item.cartEntryId, av.av, this.quantityError));
    }
    if (this.deleteDropdown) {
      this.deleteDropdown.stopLoading();
    }
    this.detectChanges();
  }

  validateSelectedQuantity(quantity: number): Observable<{ qty: number; av: AvailabilityDTO }> {
    const book = this.item.book;

    return this.availabilityService.getStoreAvailabilityWithCheck(book, book.product.ean, this.item.branch.id, quantity).pipe(
      map((resp: any) => {
        if (resp.error) {
          return { qty: 0, av: null };
        }
        if (resp && resp.av) {
          const preferedAv = resp.av.find((t) => t && t.preferred === 1);
          let preferredQty = 0;
          if (preferedAv) {
            if (allowedAvailabilityStatusCodes(preferedAv.status)) {
              preferredQty = preferedAv.qty;
            }
          }
          if (preferredQty) {
            return { qty: preferredQty, av: preferedAv as AvailabilityDTO };
          }
          return { qty: 0, av: null };
        }
        return { qty: 0, av: null };
      }),
      take(1)
    );
  }

  setQuantityError(numberOfItems: number, limit: number) {
    if (numberOfItems > 999) {
      this.quantityError = `Achtung, Maximal ${limit} Exemplare bestellbar.`;
    } else if (numberOfItems > limit) {
      this.quantityError = `${limit} Exemplar sofort lieferbar.`;
    } else {
      this.quantityError = null;
    }
  }

  deleteItem() {
    if (this.item) {
      this.delete.emit(this.item);
    }
  }

  openChangeOrderItemDialog() {
    if (!this._btnBlocked) {
      this._open = true;
      this.loadingBtn = true;
      this.modalVisible.emit(this.item.cartEntryId);
      this.detectChanges();
    }
  }

  modalReady() {
    this.loadingBtn = false;
    this.changeOrderDialog.openDialog();
  }

  modalClosed() {
    this.loadingBtn = false;
    this.modalVisible.emit(null);
    this._open = false;
    this.detectChanges();
  }

  ngOnDestroy() {
    this.destroy$.next();
  }

  // This method is needed because of the console error ViewDestroyedError: Attempt to use a destroyed view
  detectChanges() {
    setTimeout(() => {
      if (this.cdRef !== null && this.cdRef !== undefined && !(this.cdRef as ViewRef).destroyed) {
        this.cdRef.detectChanges();
      }
    }, 0);
  }
}
