import { CdkTextareaAutosize } from '@angular/cdk/text-field';
import {
  Component,
  ChangeDetectionStrategy,
  Input,
  Output,
  EventEmitter,
  ChangeDetectorRef,
  OnDestroy,
  OnInit,
  ViewChild,
} from '@angular/core';
import { FormControl } from '@angular/forms';
import { DomainOmsService, DomainReceiptService } from '@domain/oms';
import { HistoryComponent } from '@modal/history';
import { ComponentStore, tapResponse } from '@ngrx/component-store';
import { OrderDTO, OrderItemListItemDTO, ReceiptDTO, ReceiptType } from '@swagger/oms';
import { UiModalService } from '@ui/modal';
import { isEqual } from 'lodash';
import { combineLatest, NEVER } from 'rxjs';
import { catchError, filter, first, map, switchMap, withLatestFrom } from 'rxjs/operators';
import { SharedGoodsInOutOrderDetailsStore } from '../goods-in-out-order-details.store';

export interface SharedGoodsInOutOrderDetailsItemComponentState {
  orderItem?: OrderItemListItemDTO;
  order?: OrderDTO;
  quantity?: number;
  receipts?: ReceiptDTO[];
  selected?: boolean;
  more: boolean;
}

@Component({
  selector: 'shared-goods-in-out-order-details-item',
  templateUrl: 'goods-in-out-order-details-item.component.html',
  styleUrls: ['goods-in-out-order-details-item.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class SharedGoodsInOutOrderDetailsItemComponent extends ComponentStore<SharedGoodsInOutOrderDetailsItemComponentState>
  implements OnInit, OnDestroy {
  @ViewChild('autosize') autosize: CdkTextareaAutosize;

  @Input()
  get orderItem() {
    return this.get((s) => s.orderItem);
  }
  set orderItem(orderItem: OrderItemListItemDTO) {
    if (!isEqual(this.orderItem, orderItem)) {
      // Remove Prev OrderItem from selected list
      this._host.selectOrderItem(this.orderItem, false);

      this.patchState({ orderItem, quantity: orderItem?.quantity, receipts: [], more: false });
      this.specialCommentControl.reset(orderItem?.specialComment);

      // Add New OrderItem to selected list if selected was set to true by its input
      if (this.get((s) => s.selected)) {
        this._host.selectOrderItem(this.orderItem, true);
      }
      this.loadReceipts();
    }
  }

  @Input()
  get order() {
    return this.get((s) => s.order);
  }
  set order(order: OrderDTO) {
    this.patchState({ order });
  }

  @Output()
  orderItemChange = new EventEmitter<OrderItemListItemDTO>();

  readonly orderItem$ = this.select((s) => s.orderItem);

  notificationsSent$ = this.orderItem$.pipe(
    filter((oi) => !!oi),
    switchMap((oi) =>
      this._omsService
        .getCompletedTasks({ orderId: oi.orderId, orderItemId: oi.orderItemId, orderItemSubsetId: oi.orderItemSubsetId, take: 4, skip: 0 })
        .pipe(catchError(() => NEVER))
    )
  );

  canChangeQuantity$ = combineLatest([this.orderItem$, this._host.fetchPartial$]).pipe(
    map(([item, partialPickup]) => ([16, 8192].includes(item?.processingStatus) || partialPickup) && item.quantity > 1)
  );

  get quantity() {
    return this.get((s) => s.quantity);
  }
  set quantity(quantity: number) {
    if (this.quantity !== quantity) {
      this.patchState({ quantity });
    }
  }

  readonly quantity$ = this.select((s) => s.quantity);

  @Input()
  get selected() {
    return this._host.selectedeOrderItemSubsetIds.includes(this.orderItem?.orderItemSubsetId);
  }
  set selected(selected: boolean) {
    if (this.selected !== selected) {
      this.patchState({ selected });
      this._host.selectOrderItem(this.orderItem, selected);
    }
  }

  readonly selected$ = combineLatest([this.orderItem$, this._host.selectedeOrderItemSubsetIds$]).pipe(
    map(([orderItem, selectedItems]) => selectedItems.includes(orderItem?.orderItemSubsetId))
  );

  @Output()
  selectedChange = new EventEmitter<boolean>();

  get selectable() {
    return this._host.itemsSelectable && this._host.orderItems.length > 1 && this._host.fetchPartial;
  }

  readonly selectable$ = combineLatest([this._host.orderItems$, this._host.itemsSelectable$, this._host.fetchPartial$]).pipe(
    map(([orderItems, selectable, fetchPartial]) => orderItems.length > 1 && selectable && fetchPartial)
  );

  get receipts() {
    return this.get((s) => s.receipts);
  }
  set receipts(receipts: ReceiptDTO[]) {
    if (!isEqual(this.receipts, receipts)) {
      this.patchState({ receipts });
      this._host.updateReceipts(receipts);
    }
  }

  readonly receipts$ = this.select((s) => s.receipts);

  readonly receiptCount$ = this.select((s) => s.receipts?.length);

  specialCommentControl = new FormControl();

  more$ = this.select((s) => s.more);

  constructor(
    private _host: SharedGoodsInOutOrderDetailsStore,
    private _domainReceiptService: DomainReceiptService,
    private _omsService: DomainOmsService,
    private _modal: UiModalService,
    private _cdr: ChangeDetectorRef
  ) {
    super({
      more: false,
    });
  }

  ngOnInit() {}

  ngOnDestroy() {
    // Remove Prev OrderItem from selected list
    this._host.selectOrderItem(this.orderItem, false);
  }

  loadReceipts = this.effect(($) =>
    $.pipe(
      withLatestFrom(this.orderItem$),
      filter(([_, orderItem]) => !!orderItem),
      switchMap(([_, orderItem]) =>
        this._domainReceiptService
          .getReceipts({
            receiptType: 65 as ReceiptType,
            ids: [orderItem.orderItemSubsetId],
            eagerLoading: 1,
          })
          .pipe(
            tapResponse(
              (res) => {
                this.receipts = res.result.map((r) => r.item3?.data).filter((f) => !!f);
              },
              (err) => {},
              () => {}
            )
          )
      )
    )
  );

  async saveSpecialComment() {
    const { orderId, orderItemId, orderItemSubsetId } = this.orderItem;

    try {
      this.specialCommentControl.reset(this.specialCommentControl.value);
      const res = await this._omsService
        .patchComment({ orderId, orderItemId, orderItemSubsetId, specialComment: this.specialCommentControl.value ?? '' })
        .pipe(first())
        .toPromise();

      this.orderItem = { ...this.orderItem, specialComment: this.specialCommentControl.value ?? '' };
      this.orderItemChange.next(this.orderItem);
      this._host.updateOrderItems([this.orderItem]);
    } catch (error) {
      console.error(error);
    }
  }

  setMore(more: boolean) {
    this.patchState({ more });
  }

  openHistory() {
    this._modal.open({
      content: HistoryComponent,
      title: 'Historie',
      config: { showScrollbarY: false },
      data: {
        mode: 'goods',
        item: this.orderItem,
      },
    });
  }

  setSelected(selected: boolean) {
    this.selected = selected;
    this.selectedChange.emit(selected);
    this._cdr.markForCheck();
  }

  orderItemFeature(orderItemListItem: OrderItemListItemDTO) {
    const orderItems = this.order?.items;
    return orderItems.find((orderItem) => orderItem.data.id === orderItemListItem.orderItemId)?.data?.features?.orderType;
  }

  triggerResize() {
    this.autosize.reset();
  }
}
