import { Component, OnInit, OnDestroy, ViewChild, AfterContentChecked, ChangeDetectorRef } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { Observable, Subject, BehaviorSubject, of, combineLatest } from 'rxjs';
import { map, flatMap, takeUntil, filter, tap, catchError, take, withLatestFrom, switchMap } from 'rxjs/operators';
import { Store } from '@ngxs/store';
import { RemissionSelectors } from 'apps/sales/src/app/core/store/selectors/remission.selectors';
import { isNullOrUndefined } from 'util';
import {
  SetAllExistingRemissions,
  SetRemissionProcess,
  SetRemissionStarted,
  SetRemissionShippingDocument,
} from 'apps/sales/src/app/core/store/actions/remission.actions';
import { PrinterSelectionComponent } from 'apps/sales/src/app/components/printer-selection/printer-selection.component';
// tslint:disable-next-line: max-line-length
import { RemissionConfirmDeleteShippingDocumentDialogComponent } from '../../components/remission-confirm-delete-shipping-document-dialog/remission-confirm-delete-shipping-document-dialog.component';
import { AddBreadcrumb, ResetBreadcrumbsTo, DeleteLastPreviousPath } from 'apps/sales/src/app/core/store/actions/breadcrumb.actions';
import { SetBranchProcessCurrentPath } from 'apps/sales/src/app/core/store/actions/branch-process.actions';
import { ErrorService } from 'apps/sales/src/app/core/error/component/error.service';
import { Breadcrumb } from 'apps/sales/src/app/core/models/breadcrumb.model';
import { AppService } from '@sales/core-services';
import { RemissionContainerScannerScanditComponent } from 'shared/public_api';
import { RemissionProcess, RemissionService, RemissionSupplier, ShippingDocument } from '@isa/remission';

@Component({
  selector: 'app-remission-details',
  templateUrl: 'remission-details.component.html',
  styleUrls: ['./remission-details.component.scss'],
  // changeDetection: ChangeDetectionStrategy.OnPush
})
export class RemissionDetailsComponent implements OnInit, OnDestroy, AfterContentChecked {
  destroy$ = new Subject();
  isLoading = new BehaviorSubject<boolean>(false);
  isPrinting = new BehaviorSubject<boolean>(false);
  remissionProcess$: Observable<RemissionProcess>;
  isIPad = false;
  showScanner = false;

  @ViewChild('printModal')
  printModal: PrinterSelectionComponent;
  @ViewChild('remissionConfirmDeleteDialog')
  remissionConfirmDeleteDialog: RemissionConfirmDeleteShippingDocumentDialogComponent;
  @ViewChild('scanner')
  scannerComponent: RemissionContainerScannerScanditComponent;

  get shippingDocument$(): Observable<ShippingDocument> {
    return this.getShippingDocumentId().pipe(
      switchMap((id) =>
        this.getRemissionProcess().pipe(
          map((remission) => {
            return remission.shippingDocuments.find((document) => document.id === id);
          })
        )
      )
    );
  }

  get shippingDocumentCompleted$(): Observable<boolean> {
    return this.shippingDocument$.pipe(map((document) => document.isCompleted || document.isDeleted));
  }

  constructor(
    private activatedRoute: ActivatedRoute,
    private store: Store,
    private router: Router,
    private cdr: ChangeDetectorRef,
    private remissionService: RemissionService,
    private errorService: ErrorService,
    private appService: AppService
  ) {}

  ngOnInit() {
    this.isIPad = this.checkIfIpad();
    this.remissionProcess$ = this.getRemissionProcess();
  }

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

  ngAfterContentChecked() {
    this.cdr.detectChanges();
  }

  getShippingDocumentId(): Observable<number> {
    return this.activatedRoute.params.pipe(map((params) => Number(params.shippingDocumentId)));
  }

  getRemissionProcess(): Observable<RemissionProcess> {
    return this.getShippingDocumentId().pipe(flatMap(this.getRemissionFromShippingDocumentId));
  }

  openRemission(remissionProcess: RemissionProcess) {
    if (this.shouldScanToContinue(remissionProcess.shippingDocuments[0])) {
      return this.navigateToScanContainerPage();
    }

    this.setRemissionInStore(remissionProcess).pipe(takeUntil(this.destroy$), take(1)).subscribe(this.navigateToRemissionStartedPage);
  }

  private navigateToScanContainerPage = () => {
    this.showScanner = true;
    this.cdr.detectChanges();
    this.scannerComponent.openNativeScanner();
  };

  shippingDocumentScanned(receiptNumber: string) {
    this.store
      .select(RemissionSelectors.getAllRemissions)
      .pipe(
        takeUntil(this.destroy$),
        map((remissionProcesses) =>
          remissionProcesses.find(
            (remissionProcess) =>
              remissionProcess.shippingDocuments[0] && remissionProcess.shippingDocuments[0].shippingDocumentNumber === receiptNumber
          )
        )
      )
      .subscribe(this.shippingDocumentScannedResultHandler);
  }

  private shippingDocumentScannedResultHandler = (remissionProcess: RemissionProcess) => {
    this.showScanner = false;
    this.cdr.detectChanges();

    this.setRemissionInStore(remissionProcess).pipe(takeUntil(this.destroy$), take(1)).subscribe(this.navigateToRemissionStartedPage);
  };

  private setRemissionInStore(remissionProcess: RemissionProcess) {
    return this.store.dispatch(new SetRemissionProcess(remissionProcess, true)).pipe(
      map((_) => this.store.dispatch(new SetRemissionShippingDocument(remissionProcess.shippingDocuments[0]))),
      map((_) => this.store.dispatch(new SetRemissionStarted(true)))
    );
  }

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

  deleteShippingDocument() {
    this.remissionProcess$
      .pipe(
        takeUntil(this.destroy$),
        filter((remissionProcess) => {
          const shippingDocument = remissionProcess.shippingDocuments[0];
          if (!shippingDocument) {
            return false;
          }

          if (this.hasProducts(shippingDocument)) {
            this.remissionConfirmDeleteDialog.openDialog();
            return false;
          }

          return true;
        }),
        withLatestFrom(this.getShippingDocumentId()),
        flatMap(([remissionProcess, shippingDocumentId]) =>
          this.remissionService
            .deleteShippingDocument({
              remissionProcessId: remissionProcess.id,
              shippingDocumentId,
              externalId: remissionProcess.externalId,
            })
            .pipe(map((response) => response.result))
        )
      )
      .subscribe(this.handleDeleteResult);
  }

  confirmDeleteShippingDocument() {
    combineLatest([this.remissionProcess$, this.getShippingDocumentId()])
      .pipe(
        takeUntil(this.destroy$),
        flatMap(([remissionProcess, shippingDocumentId]) =>
          this.remissionService
            .deleteShippingDocument({
              remissionProcessId: remissionProcess.id,
              shippingDocumentId,
              externalId: remissionProcess.externalId,
            })
            .pipe(map((response) => response.result))
        )
      )
      .subscribe(this.handleDeleteResult);
  }

  private handleDeleteResult = (result: { deleted: boolean; completedRemissionsExist: boolean }) => {
    if (!result.deleted) {
      return this.handleDeleteError('Fehler beim Löschen des Warenbegleitscheins');
    }

    if (result.completedRemissionsExist) {
      return this.navigateToCompleteRemissionPage();
    }

    return this.navigateToOverviewPage();
  };

  private handleDeleteError = (errorMessage: string) => {
    this.errorService.addErrors(400, errorMessage, errorMessage);
  };

  navigateToOverviewPage = () => {
    const path = 'remission/overview';
    this.store.dispatch(
      new AddBreadcrumb(
        {
          path: path,
          name: 'Offene Warenbegleitscheine',
        },
        'remission'
      )
    );
    this.store.dispatch(new SetBranchProcessCurrentPath(path, true));
    this.router.navigate([path]).then((_) => {
      this.store.dispatch(new DeleteLastPreviousPath());
    });
  };

  navigateToCompleteRemissionPage = () => {
    const path = '/remission/finish';
    this.store.dispatch(
      new AddBreadcrumb(
        {
          path: path,
          name: 'Wannennummer',
        },
        'remission'
      )
    );
    this.router.navigate([path]);
    this.store.dispatch(new SetBranchProcessCurrentPath(path));
  };

  openPrintSelection() {
    this.printModal.openDialog();
  }

  print(printerKey: string) {
    this.isPrinting.next(true);

    this.remissionProcess$
      .pipe(
        takeUntil(this.destroy$),
        map((remission) => remission.id),
        flatMap((remissionProcessId) =>
          this.remissionService
            .printShippingDocument({
              remissionProcessId,
              printerKey,
            })
            .pipe(
              catchError((_) => {
                this.isLoading.next(false);
                return of(false);
              })
            )
        )
      )
      .subscribe(this.printSubscriptionHandler, this.printErrorHandler);
  }

  private printSubscriptionHandler = () => {
    this.isPrinting.next(false);
    this.printModal.closeModal();
  };

  private printErrorHandler = () => {
    this.isPrinting.next(false);
  };

  private getRemissionFromShippingDocumentId = (shippingDocumentId: number): Observable<RemissionProcess> => {
    const allRemissions$ = this.store.select(RemissionSelectors.getAllRemissions);

    return allRemissions$.pipe(
      takeUntil(this.destroy$),
      tap((allRemissions) => {
        if (isNullOrUndefined(allRemissions)) {
          this.isLoading.next(true);
          this.loadAllRemissions();
        }
      }),
      filter((allRemissions) => !isNullOrUndefined(allRemissions)),
      map((allRemissions) =>
        allRemissions.find((remission) => remission.shippingDocuments[0] && remission.shippingDocuments[0].id === shippingDocumentId)
      )
    );
  };

  private loadAllRemissions() {
    this.remissionService
      .getAllRemissions({
        showOpen: true,
        showCompleted: true,
        showCompletedLastWeekOnly: true,
        take: 200,
      })
      .pipe(
        takeUntil(this.destroy$),
        filter((remissionProcesses) => !isNullOrUndefined(remissionProcesses))
      )
      .subscribe(this.allRemissionsSubscriptionHandler);
  }

  private allRemissionsSubscriptionHandler = (remissionProcesses: RemissionProcess[]) => {
    this.isLoading.next(false);
    this.store.dispatch(new SetAllExistingRemissions(remissionProcesses));
  };

  private hasProducts(shippingDocument: ShippingDocument): boolean {
    return !!shippingDocument.products.length;
  }

  private checkIfIpad(): boolean {
    return this.appService.isIPadEnv();
  }

  private isShippingDocumentGenerated(shippingDocument: ShippingDocument): boolean {
    // 9 indicates that document has been generated
    return shippingDocument.shippingDocumentNumber[6] === '9';
  }

  shouldScanToContinue(shippingDocument: ShippingDocument): boolean {
    return !this.isShippingDocumentGenerated(shippingDocument) && !!this.isIPad;
  }

  isSupplierActivatedForPrinting(supplier: RemissionSupplier) {
    switch (supplier.id) {
      case 1:
        return true;
      case 2:
        return false;

      default:
        return true;
    }
  }
}
