import { Injectable } from '@angular/core';
import { ArticleDTO, DisplayInfoDTO, EISPublicDocumentService } from '@swagger/eis';
import {
  CatalogPrintService,
  CheckoutPrintService,
  ItemDTO,
  OMSPrintService,
  PriceQRCodeDTO,
  PrintRequestOfIEnumerableOfItemDTO,
  PrintRequestOfIEnumerableOfLong,
  PrintRequestOfIEnumerableOfPriceQRCodeDTO,
  PrintService,
  ResponseArgs,
} from '@swagger/print';
import { Observable, of } from 'rxjs';
import { catchError, filter, map, switchMap, timeout } from 'rxjs/operators';
import { Printer } from './defs/printer.model';

@Injectable({
  providedIn: 'root',
})
export class DomainPrinterService {
  constructor(
    private printService: PrintService,
    private oMSPrintService: OMSPrintService,
    private catalogPrintService: CatalogPrintService,
    private checkoutPrintService: CheckoutPrintService,
    private eisPublicDocumentService: EISPublicDocumentService
  ) {}

  getAvailablePrinters(): Observable<Printer[] | { error: string }> {
    return this.printService.PrintPrinters().pipe(
      catchError((error) => of({ error })),
      map((response: any) => {
        if (response.error && response.error.status === 503) {
          return {
            error: response.message ? response.message : 'Das Backend ist derzeit nicht erreichbar',
          };
        }
        if (response.error && response.error.name === 'TimeoutError') {
          return { error: response.message ? response.message : 'API Timeout' };
        }
        if (response.error) {
          return {
            error: response.message ? response.message : response.error.message ? response.error.message : 'Ein Fehler ist aufgetreten',
          };
        }

        return response.result.map(
          (t) =>
            <Printer>{
              key: t.key,
              value: t.value,
              description: t.description,
              selected: t.selected,
            }
        );
      })
    );
  }

  getAvailableOfficePrinters(): Observable<Printer[] | { error: string }> {
    return this.printService.PrintOfficePrinters().pipe(
      catchError((error) => of({ error })),
      map((response: any) => {
        if (response.error && response.error.status === 503) {
          return {
            error: response.message ? response.message : 'Das Backend ist derzeit nicht erreichbar',
          };
        }
        if (response.error && response.error.name === 'TimeoutError') {
          return { error: response.message ? response.message : 'API Timeout' };
        }
        if (response.error) {
          return {
            error: response.message ? response.message : response.error.message ? response.error.message : 'Ein Fehler ist aufgetreten',
          };
        }

        return response.result.map(
          (t) =>
            <Printer>{
              key: t.key,
              value: t.value,
              description: t.description,
              selected: t.selected,
            }
        );
      })
    );
  }

  getAvailableLabelPrinters(): Observable<Printer[] | { error: string }> {
    return this.printService.PrintLabelPrinters().pipe(
      catchError((error) => of({ error })),
      map((response: any) => {
        if (response.error && response.error.status === 503) {
          return {
            error: response.message ? response.message : 'Das Backend ist derzeit nicht erreichbar',
          };
        }
        if (response.error && response.error.name === 'TimeoutError') {
          return { error: response.message ? response.message : 'API Timeout' };
        }
        if (response.error) {
          return {
            error: response.message ? response.message : response.error.message ? response.error.message : 'Ein Fehler ist aufgetreten',
          };
        }

        return response.result.map(
          (t) =>
            <Printer>{
              key: t.key,
              value: t.value,
              description: t.description,
              selected: t.selected,
            }
        );
      })
    );
  }

  printOrder({ orderIds, printer }: { orderIds: number[]; printer: string }): Observable<ResponseArgs> {
    const params = <any>{
      printer: printer,
      data: orderIds,
    };
    return this.oMSPrintService.OMSPrintAbholscheinById(params).pipe(timeout(20000));
  }

  printShippingNote({ receipts, printer }: { receipts: number[]; printer: string }) {
    return this.oMSPrintService.OMSPrintLieferschein({
      printer,
      data: receipts,
    });
  }

  printCompartmentLabel({ orderItemSubsetIds, printer }: { orderItemSubsetIds: number[]; printer: string }) {
    return this.oMSPrintService.OMSPrintAbholfachetikett({
      printer,
      data: orderItemSubsetIds,
    });
  }

  printProduct({ item, printer }: { item: ItemDTO; printer: string }): Observable<ResponseArgs> {
    const params = <PrintRequestOfIEnumerableOfItemDTO>{
      printer: printer,
      data: [item],
    };
    return this.catalogPrintService.CatalogPrintArtikelDetail(params).pipe(timeout(20000));
  }

  printCart({ cartId, printer }: { cartId: number; printer: string }): Observable<ResponseArgs> {
    const params = <any>{
      printer: printer,
      data: cartId,
    };
    return this.checkoutPrintService.CheckoutPrintWarenkorbById(params).pipe(timeout(20000));
  }

  async printGoodsInLabel(subsetItemIds: number[]): Promise<ResponseArgs> {
    const response = await this.getAvailablePrinters()
      .pipe(
        filter((data) => Array.isArray(data)),
        switchMap((printers: Printer[]) => {
          if (printers && printers.length > 0) {
            const printer = printers.find((p) => p.selected);
            if (printer) {
              const params = <PrintRequestOfIEnumerableOfLong>{
                data: subsetItemIds,
                printer: printer.key,
              };
              return this.oMSPrintService.OMSPrintAbholfachetikett(params);
            } else {
              return of(undefined);
            }
          } else {
            return of(undefined);
          }
        }),
        timeout(20000)
      )
      .toPromise();

    return response;
  }

  printPdf({ printer, data }: { printer: string; data: string }) {
    return this.printService.PrintPrintPdf({
      printer,
      data,
    });
  }

  printDisplayInfoDTOArticles({
    articles,
    printer,
    title,
  }: {
    articles: ArticleDTO[];
    printer: string;
    title?: string;
  }): Observable<ResponseArgs> {
    return this.eisPublicDocumentService
      .EISPublicDocumentGetArticlesPdfAsBase64({
        payload: { data: articles.map((article) => article.ean), title },
      })
      .pipe(
        switchMap((res) => {
          if (!res.error) {
            return this.printPdf({ printer, data: res.result });
          }
          return of(res);
        })
      );
  }

  printDisplayInfoDTOList({ displayInfos, printer, title }: { displayInfos: DisplayInfoDTO[]; printer: string; title?: string }) {
    return this.eisPublicDocumentService
      .EISPublicDocumentGetInfosPdfAsBase64({
        payload: { data: displayInfos, title },
      })
      .pipe(
        switchMap((res) => {
          if (!res.error) {
            return this.printPdf({ printer, data: res.result });
          }
          return of(res);
        })
      );
  }

  printQrCode(data: PrintRequestOfIEnumerableOfPriceQRCodeDTO) {
    return this.oMSPrintService.OMSPrintPriceQRCode(data);
  }
}
