import { Component, ChangeDetectionStrategy, Input, OnDestroy } from '@angular/core';
import { DomainRemissionService, RemissionListItem } from '@domain/remission';
import { RemissionPlacementType } from '@isa/remission';
import {
  ReturnDTO,
  ValueTupleOfReceiptItemDTOAndReturnItemDTO,
  ValueTupleOfReceiptItemDTOAndReturnSuggestionDTO,
  ReturnItemDTO,
  ReturnSuggestionDTO,
} from '@swagger/remi';
import { UiDialogModalComponent, UiErrorModalComponent, UiModalService } from '@ui/modal';
import { mapFromReturnItemDTO, mapFromReturnSuggestionDTO } from 'apps/domain/remission/src/lib/mappings';
import { BehaviorSubject, Subject } from 'rxjs';
import { first, takeUntil } from 'rxjs/operators';
import { AddProductToShippingDocumentModalComponent } from '../../modals/add-product-to-shipping-document-modal/add-product-to-shipping-document-modal.component';
import { RemissionListComponentStore } from '../remission-list.component-store';

@Component({
  selector: 'page-remission-list-item',
  templateUrl: 'remission-list-item.component.html',
  styleUrls: ['remission-list-item.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class RemissionListItemComponent implements OnDestroy {
  private _onDestroy$ = new Subject();

  @Input()
  item: RemissionListItem;

  @Input()
  returnDto: ReturnDTO;

  get contributors() {
    return this.item?.dto?.product?.contributors?.split(';').map((val) => val.trim());
  }

  get firstReceipt() {
    return this.returnDto?.receipts?.find((_) => true)?.data;
  }

  get enableToRemit() {
    return this.item.inStock > 0 && this.item.remissionQuantity > 0;
  }

  get enableChangeRemissionQuantity() {
    return this.enableToRemit ? this.item.inStock > 0 && this.item.remissionQuantity > 0 : this.item.remissionQuantity > 0;
  }

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

  constructor(
    private _modal: UiModalService,
    private _remissionService: DomainRemissionService,
    private _store: RemissionListComponentStore
  ) {}

  ngOnDestroy() {
    this._onDestroy$.next();
    this._onDestroy$.complete();
  }

  addProductToShippingDocument() {
    const modal = this._modal.open({
      content: AddProductToShippingDocumentModalComponent,
      title: 'Remi-Menge / Platzierung ändern',
      data: {
        item: this.item,
        returnDto: this.returnDto,
      },
    });

    modal.afterClosed$.pipe(takeUntil(this._onDestroy$)).subscribe((result) => {
      if (result?.data?.action === 'remit') {
        this.addReturnItemOrSuggestion({
          quantity: result.data.quantity,
          placementType: result.data.placementType,
          impedimentComment: this.item.remissionQuantity > result.data.quantity ? 'Restmenge' : '',
          remainingQuantity: this.item.inStock - result.data.quantity <= 0 ? null : this.item.inStock - result.data.quantity,
        });
      } else if (result?.data?.action === 'notFound') {
        this.returnImpediment();
      }
    });
  }

  remit() {
    const modal = this._modal.open({
      content: UiDialogModalComponent,
      title: 'Remittieren',
      data: {
        content: `Sie sind gerade dabei alle ${this.item.remissionQuantity} Exemplare von einem ${
          this.item.placementType && this.item.placementType === 'Stapel' ? 'Stapel' : 'Leistungsplatz'
        } zu\nremittieren. Sind wirklich alle Exemplare in ${
          this.item.placementType && this.item.placementType === 'Stapel' ? 'dem Stapel' : 'der Leistung'
        }?`,
        actions: [
          { label: 'Ja', selected: true, command: 'remit' },
          { label: 'Abbrechen', command: 'close' },
        ],
      },
    });

    modal.afterClosed$.pipe(takeUntil(this._onDestroy$)).subscribe((result) => {
      if (result?.data === 'remit') {
        this.addReturnItemOrSuggestion({ quantity: this.item.remissionQuantity });
      }
    });
  }

  async removeReturnItem() {
    this.loading$.next(true);
    try {
      await this._remissionService.removeReturnItemFromList({ itemId: this.item?.dto?.id }).toPromise();
      this._store.removeItem(this.item);
    } catch (err) {
      this._modal.open({
        content: UiErrorModalComponent,
        title: 'Fehler beim entfernen eines Artikels von der Remissionsliste',
        data: err?.status === 404 ? { message: 'Artikel wurde bereits entfernt.' } : err,
      });
      this.reload();
    }
    this.loading$.next(false);
  }

  async addReturnItemOrSuggestion({
    quantity,
    placementType,
    impedimentComment,
    remainingQuantity,
  }: {
    quantity?: number;
    placementType?: RemissionPlacementType;
    impedimentComment?: string;
    remainingQuantity?: number;
  }) {
    this.loading$.next(true);
    try {
      let response: ValueTupleOfReceiptItemDTOAndReturnItemDTO | ValueTupleOfReceiptItemDTOAndReturnSuggestionDTO;

      // Pflichtremission
      if (this.item.dtoType === 'return') {
        response = await this._remissionService
          .addReturnItem({
            returnId: this.returnDto.id,
            receiptId: this.firstReceipt.id,
            returnItemId: this.item.dto.id,
            inStock: this.item.inStock,
            quantity,
            placementType,
          })
          .toPromise();
      }
      // Abteilungsremission
      else if (this.item.dtoType === 'suggestion') {
        response = await this._remissionService
          .addReturnSuggestion({
            returnId: this.returnDto.id,
            receiptId: this.firstReceipt.id,
            returnSuggestionId: this.item.dto.id,
            inStock: this.item.inStock,
            quantity,
            placementType,
            impedimentComment,
            remainingQuantity,
          })
          .toPromise();
      } else {
        throw new Error('Item hat keinen passenden DTO Typ');
      }

      // Bei remittieren eines Stapels die StockInformation für alle anderen Stapel mit der selben EAN aktualisieren
      if (placementType != 'Leistung') {
        const items = await this._store.items$.pipe(first()).toPromise();

        const itemsByEan = items?.filter(
          (i) => i.dto.product.ean === this.item.dto.product.ean && i.dto.id !== this.item.dto.id && i.placementType === 'Stapel'
        );

        if (itemsByEan?.length > 0) {
          const updatedItems = await this.updateStockInformation(itemsByEan, true);
          updatedItems.forEach((i) => this._store.updateItem(i));
        }
      }

      this._store.removeItem(this.item);
      if (response && !!response?.item2) {
        response.item2.placementType = placementType;
        await this.addItem(response.item2);
      }

      this._store.updateCache();
    } catch (err) {
      this._modal.open({
        content: UiErrorModalComponent,
        title: 'Fehler beim remittieren',
        data: err?.status === 409 ? { message: 'Artikel wurde bereits remittiert.' } : err,
      });
      this.reload();
    }
    this.loading$.next(false);
  }

  async returnImpediment() {
    this.loading$.next(true);

    let updatedDto: ReturnItemDTO | ReturnSuggestionDTO;

    try {
      // Pflichtremission
      if (this.item.dtoType === 'return') {
        updatedDto = await this._remissionService.returnImpediment(this.item.dto?.id).toPromise();
      }
      // Abteilungsremission
      else if (this.item.dtoType === 'suggestion') {
        updatedDto = await this._remissionService.returnSuggestion(this.item.dto?.id).toPromise();
      }

      if (updatedDto.impediment?.attempts === 1 && updatedDto.returnReason.startsWith('Abholfach:')) {
        this._store.removeItem(this.item);
      } else if (updatedDto.impediment?.attempts > 3) {
        this._store.removeItem(this.item);
      } else {
        this._store.updateItemDto(updatedDto);
      }
      this._store.updateCache();
    } catch (err) {
      this._modal.open({
        content: UiErrorModalComponent,
        title: 'Fehler bei Artikel nicht gefunden',
        data: err,
      });
      this.reload();
    }
    this.loading$.next(false);
  }

  reload() {
    this._store.search({ newSearch: true });
  }

  async addItem(responseItem: ReturnItemDTO | ReturnSuggestionDTO) {
    let item: RemissionListItem;
    if (this.item.dtoType === 'return') {
      item = mapFromReturnItemDTO(responseItem);
    } else if (this.item.dtoType === 'suggestion') {
      item = mapFromReturnSuggestionDTO(responseItem);
    } else {
      throw new Error('Fehler beim Mapping der DTO');
    }

    if (!this.item.remissionReason) {
      delete item.remissionReason;
    }

    // Anzeige der Remi-Menge und des aktuellen Bestands aktualisieren
    const items = await this.updateStockInformation([item], false);

    this._store.addItems(items);
  }

  async updateStockInformation(items: RemissionListItem[], recalculate: boolean) {
    try {
      const res = await this._remissionService.getStockInformation(items, recalculate).toPromise();
      items.forEach((item) => {
        const resForItem = res.find((r) => r.dto.id === item.dto.id);
        item.remissionQuantity = resForItem?.remissionQuantity;
        item.remainingQuantity = resForItem?.remainingQuantity;
        item.inStock = resForItem?.inStock;
      });
      return items;
    } catch (err) {
      throw new Error('Fehler bei der Bestandsabfrage');
    }
  }
}
