import { Component, OnInit, OnDestroy, ChangeDetectorRef, ViewChild } from '@angular/core';
import { RemissionFinishingProcessStatus } from '../../models/remission-finishing-process-status.enum';
import { Store, Select } from '@ngxs/store';
import { RemissionSelectors } from 'apps/sales/src/app/core/store/selectors/remission.selectors';
import { RemissionSupplier, RemissionProcess, RemissionService, ShippingDocument, Printer } from '@isa/remission';
import { filter, takeUntil, take, switchMap, map, tap } from 'rxjs/operators';
import { isNullOrUndefined } from 'util';
import { Subject, Observable, merge } from 'rxjs';
import { SUPPLIER_PLACEHOLDER } from '../../constants/remission.constants';
import { AddBreadcrumb, ResetBreadcrumbsTo } from 'apps/sales/src/app/core/store/actions/breadcrumb.actions';
import { SetBranchProcessCurrentPath } from 'apps/sales/src/app/core/store/actions/branch-process.actions';
import { Router } from '@angular/router';
import {
  ResetRemissionState,
  SetRemissionFinishedProcessStatus,
  SetRemissionScannedContainerId,
  SetRemissionStarted,
  SetRemissionProcess,
  ResetRemissionShippingDocument,
  CompleteRemissionShippingDocument,
} from 'apps/sales/src/app/core/store/actions/remission.actions';
import { Breadcrumb } from 'apps/sales/src/app/core/models/breadcrumb.model';
import { AppService } from '@sales/core-services';
// tslint:disable-next-line: max-line-length
import { RemissionScanProductInvalidBarcodeComponent } from '../../components/remission-scan-product-invalid-barcode/remission-scan-product-invalid-barcode.component';
import { NativeContainerService } from 'shared/lib/remission-container-scanner/native-container.service';
// tslint:disable-next-line: max-line-length
import { RemissionScanShippingDocumentClosedComponent } from '../../components/remission-scan-shipping-document-closed/remission-scan-shipping-document-closed.component';
import { RemissionProcessStatuses } from 'apps/sales/src/app/core/models/remission-process-statuses.model';
import { PrinterSelectionComponent } from 'apps/sales/src/app/components/printer-selection/printer-selection.component';
import { RemissionScanConfirmationDialogComponent } from '../../components/remission-scan-confirmation-dialog';

@Component({
  selector: 'app-remission-finish',
  templateUrl: './remission-finish.component.html',
  styleUrls: ['./remission-finish.component.scss'],
})
export class RemissionFinishComponent implements OnInit, OnDestroy {
  @Select(RemissionSelectors.getRemissionProcess) remissionProcess$: Observable<RemissionProcess>;
  @Select(RemissionSelectors.getRemissionShippingDocument)
  shippingDocument$: Observable<ShippingDocument>;
  @Select(RemissionSelectors.getRemissionShippingDocumentstatus)
  shippingDocumentStatus$;
  @Select(RemissionSelectors.getRemissionProcess)
  currentRemissionProcess$: Observable<RemissionProcess>;
  @Select(RemissionSelectors.getRemissionProcessStatuses)
  remissionProcessStatuses$: Observable<RemissionProcessStatuses>;
  @ViewChild('invalidBarcodeDialog')
  invalidBarcodeDialog: RemissionScanProductInvalidBarcodeComponent;
  @ViewChild('invalidDocumentDialog')
  invalidDocumentDialog: RemissionScanShippingDocumentClosedComponent;
  @ViewChild('printModal')
  printModal: PrinterSelectionComponent;
  @ViewChild('confirmScanModal')
  confirmScanModal: RemissionScanConfirmationDialogComponent;
  pageStatus: RemissionFinishingProcessStatus;
  suppliers: {
    leftSupplier: RemissionSupplier;
    rightSupplier: RemissionSupplier;
  };
  remissionProcess: RemissionProcess;
  shippingDocument: ShippingDocument;
  destroy$ = new Subject();
  containerId: string;
  showError = false;
  errorMsg = 'Leider haben Sie den falschen Barcode gescannt. Scannen Sie bitte den Barcode seitlich an der Wanne.';
  supplier: RemissionSupplier;
  startNewRemission = false;
  title = {
    0: 'Wannennummer scannen',
    1: 'Wanne abgeschlossen',
    2: ``,
  };
  isSafari = false;
  isNative = false;
  emptyOrInvalidBarcode = true;
  isPrinting = false;

  subTitle = {
    0: 'Scannen Sie die Wannennummer um den Warenbegleitschein abzuschließen.',
    // tslint:disable-next-line: max-line-length
    1: 'Legen Sie abschließend den "Blank Beizettel" in die abgeschlossene Wanne. Der Warenbegleitschein wird nach Abschluss der Remission versendet. Zum Öffnen eines neuen Warenbegleitscheins setzen Sie die Remission fort.',
    2: '',
  };

  private finishPocessTitles = {
    1: `${SUPPLIER_PLACEHOLDER} Warenbegleitschein gedruckt`,
    2: `Warenbegleitschein versendet`,
  };

  private finishPocessSubTitles = {
    1: `Die Warenbegleitscheine für ${SUPPLIER_PLACEHOLDER} werden gedruckt. Bitte in die Wanne legen.`,
    2: `Der Warenbegleitschein wurde digital an ${SUPPLIER_PLACEHOLDER} versendet.`,
  };

  constructor(
    private store: Store,
    private router: Router,
    private remissionService: RemissionService,
    private cdrf: ChangeDetectorRef,
    private appService: AppService,
    private nativeContainerService: NativeContainerService
  ) {}

  ngOnInit() {
    this.initialize();
    const { isSafari, isNative } = this.nativeContainerService.isUiWebview();
    this.isSafari = isSafari;
    this.isNative = isNative;
  }

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

  initialize() {
    this.store
      .select(RemissionSelectors.getRemissionFinishingProcessStatus)
      .pipe(
        takeUntil(this.destroy$),
        filter((data) => !isNullOrUndefined(data)),
        take(1)
      )
      .subscribe((status) => {
        this.pageStatus = status;
        this.cdrf.detectChanges();
        if (this.pageStatus === RemissionFinishingProcessStatus.containerScanned) {
          this.containerId = this.store.selectSnapshot(RemissionSelectors.getRemissionContainerId);
        } else if (this.pageStatus === RemissionFinishingProcessStatus.notSet) {
          this.navigateToNewRemissionList();
        }
      });
    this.remissionProcess$
      .pipe(
        filter((data) => !isNullOrUndefined(data)),
        take(1),
        takeUntil(this.destroy$)
      )
      .subscribe(this.remissionProcessSubscriptionHandler);

    this.shippingDocument$
      .pipe(
        filter((data) => !isNullOrUndefined(data)),
        takeUntil(this.destroy$)
      )
      .subscribe(this.shippingDocumentSubscriptionHandler);

    this.loadCurrentRemissionProcessStatuses().then(() => {
      this.continueProcess()
        .pipe(takeUntil(this.destroy$), take(1))
        .subscribe((remission) => {
          if (this.shippingDocument && this.shippingDocument.id) {
            this.loadSupplier(remission.filter.target);
            this.remissionService
              .getShippingDocuments({
                remissionProcessId: this.remissionProcess.id,
                shippingDocumentId: this.shippingDocument.id,
              })
              .pipe(
                filter((data) => !isNullOrUndefined(data)),
                takeUntil(this.destroy$)
              )
              .subscribe(({ isCompleted }) => {
                if (isCompleted) {
                  this.pageStatus = RemissionFinishingProcessStatus.containerScanned;
                }
              });
          }
        });
    });
  }

  loadCurrentRemissionProcessStatuses() {
    return this.remissionProcessStatuses$
      .pipe(
        filter((data) => !isNullOrUndefined(data)),
        take(1)
      )
      .toPromise();
  }

  loadCurrentRemissionProcess() {
    return this.currentRemissionProcess$.pipe(filter((data) => !isNullOrUndefined(data), take(1)));
  }

  continueProcess() {
    return this.loadCurrentRemissionProcess().pipe(
      take(1),
      switchMap((remissionProcess) => {
        return this.remissionService.continueProcess(remissionProcess);
      })
    );
  }

  shippingDocumentSubscriptionHandler = (shippingDocument: ShippingDocument) => {
    this.shippingDocument = shippingDocument;
  };

  remissionProcessSubscriptionHandler = (remissionProcess: RemissionProcess) => {
    this.remissionProcess = remissionProcess;
    if (remissionProcess && remissionProcess.filter && remissionProcess.filter.target) {
      this.loadSupplier(remissionProcess.filter.target);
    }
  };

  loadSupplier(remissionSuplier: RemissionSupplier) {
    this.supplier = remissionSuplier;
    if (remissionSuplier.id === 1) {
      this.subTitle[RemissionFinishingProcessStatus.containerScanned] =
        // tslint:disable-next-line: max-line-length
        'Der Warenbegleitschein wird nach Abschluss der Remission gedruckt. Zum Öffnen eines neuen Warenbegleitscheins setzen Sie die Remission fort.';
    }
    if (this.supplier) {
      const selectedSupplierName = remissionSuplier.name;
      this.title[RemissionFinishingProcessStatus.finished] = this.finishPocessTitles[this.supplier.id].replace(
        SUPPLIER_PLACEHOLDER,
        selectedSupplierName
      );
      this.subTitle[RemissionFinishingProcessStatus.finished] = this.finishPocessSubTitles[this.supplier.id].replace(
        SUPPLIER_PLACEHOLDER,
        selectedSupplierName
      );
    }
  }

  private openConfirmationDialog(barcode: string) {
    this.confirmScanModal.openDialog(barcode);
  }

  retryScan() {
    const path = '/remission/finish';
    this.router.navigate([path]);
  }

  completeScan(barcode: string) {
    this.showError = false;
    this.containerId = barcode;
    this.store.dispatch(new SetRemissionScannedContainerId(this.containerId));
    this.completeShippingDocument();
  }

  abandonScan() {
    this.store.dispatch(new SetBranchProcessCurrentPath('remission', false));
    this.store
      .dispatch(new SetRemissionFinishedProcessStatus(RemissionFinishingProcessStatus.notSet))
      .toPromise()
      .then((_) => {
        this.router.navigate(['remission/started']);
      });
  }

  handleScanResult(barcode: string) {
    if (!barcode) {
      return this.showInvalidBarcodeDialog();
    }

    return this.openConfirmationDialog(barcode);
  }

  finishRemission() {
    const remissionProcessId = this.remissionProcess.id;
    this.remissionService.isPrintingRequired({ remissionProcessId }).subscribe((isPrintingRequired) => {
      if (isPrintingRequired) {
        this.printModal.openDialog();
      } else {
        this.postFinishRemission(remissionProcessId);
      }
    });
  }

  print(selectedPrinter) {
    this.isPrinting = true;
    this.remissionService
      .printShippingDocument({
        remissionProcessId: this.remissionProcess.id,
        printerKey: selectedPrinter,
      })
      .subscribe(
        () => {
          this.isPrinting = false;
          this.printModal.closeModal();
          this.postFinishRemission(this.remissionProcess.id);
        },
        () => {
          this.pageStatus = RemissionFinishingProcessStatus.containerScanned;
          this.store.dispatch(new SetRemissionFinishedProcessStatus(this.pageStatus));
          this.isPrinting = false;
        }
      );
  }

  postFinishRemission(remissionProcessId: number) {
    this.remissionService.completeRemissions({ remissionProcessId }).subscribe((status) => {
      if (status) {
        this.appService.clearIdleReminder();
        this.pageStatus = RemissionFinishingProcessStatus.finished;
        this.store.dispatch(new SetRemissionFinishedProcessStatus(this.pageStatus));
        this.store.dispatch(new ResetRemissionState());
      }
    });
  }

  continueRemission() {
    this.startRemission();
  }

  navigateToNewRemissionList() {
    this.store.dispatch(new ResetRemissionState());
    const path = '/remission/create';
    this.store.dispatch(
      new ResetBreadcrumbsTo(
        <Breadcrumb>{
          name: 'Remission',
          path: path,
        },
        'remission',
        true
      )
    );
    this.store.dispatch(new SetBranchProcessCurrentPath(path));
    this.router.navigate([path]);
  }

  startRemission() {
    try {
      throw new Error('[Remission Finished] Start Remission');
    } catch (error) {
      console.error(error);
    }
    this.remissionService
      .startRemission({ remissionProcessId: this.remissionProcess.id })
      .pipe(
        filter((data) => !isNullOrUndefined(data)),
        take(1),
        tap((process) => console.log('[Remission Finished] Start Remission II', process))
      )
      .subscribe((remissionProcess) => {
        this.store.dispatch(new SetRemissionStarted(true));
        this.store.dispatch(new SetRemissionProcess(remissionProcess));
        this.navigateToStartedRemission();
      });
  }

  navigateToStartedRemission() {
    this.store.dispatch(new ResetRemissionShippingDocument());
    const path = '/remission/started';
    this.store.dispatch(
      new AddBreadcrumb(
        {
          path: path,
          name: 'Warenbegleitschein',
        },
        'remission'
      )
    );
    this.store.dispatch(new SetBranchProcessCurrentPath(path, true));
    this.router.navigate([path]);
  }

  private completeShippingDocument() {
    this.remissionService
      .completeShippingDocument({
        remissionProcessId: this.remissionProcess.id,
        shippingDocumentId: this.shippingDocument.id,
        containerId: this.containerId,
      })
      .subscribe((response) => {
        if (response.error) {
          if (response.errorReasons.PackageCode) {
            this.emptyOrInvalidBarcode = false;
            this.pageStatus = RemissionFinishingProcessStatus.start;
            this.store.dispatch(new SetRemissionFinishedProcessStatus(this.pageStatus));
            this.showInvalidBarcodeDialog();
          } else {
            this.invalidDocumentDialog.openDialog();
          }
        } else {
          this.pageStatus = RemissionFinishingProcessStatus.containerScanned;
          this.store.dispatch(new CompleteRemissionShippingDocument(this.shippingDocument));
        }
      });
  }

  private showInvalidBarcodeDialog() {
    const closeDialogRef = this.invalidBarcodeDialog.openDialog();
    closeDialogRef.subscribe(() => (this.emptyOrInvalidBarcode = true));
  }
}
