import { Component, OnInit, OnDestroy, Input } from '@angular/core';
import { ModalService, ButtonComponent } from '@libs/ui';
import { Breadcrumb } from '../../../../core/models/breadcrumb.model';
import { ChangeCurrentRoute, EmptyFinishedOrders } from '../../../../core/store/actions/process.actions';
import { Store, Select } from '@ngxs/store';
import { Router } from '@angular/router';
import { AddBreadcrumb } from '../../../../core/store/actions/breadcrumb.actions';
import { Process } from '../../../../core/models/process.model';
import { ProcessSelectors } from '../../../../core/store/selectors/process.selectors';
import { Observable, Subject, of, forkJoin } from 'rxjs';
import { takeUntil, switchMap, filter, map } from 'rxjs/operators';
import { CheckoutService } from '../../../../core/services/checkout.service';
import { CheckoutDTO, EntityDTOContainerOfDestinationDTO } from '@swagger/checkout';
import { SetPaymentTypeToCheckout, SetDestinationToCheckout, SetNotificationChannel } from '../../../../core/store/actions/cart.actions';
import { User } from '../../../../core/models/user.model';
import { CustomerSelectors } from 'apps/sales/src/app/core/store/selectors/customer.selectors';
import { isNullOrUndefined } from 'util';
import { SharedSelectors } from 'apps/sales/src/app/core/store/selectors/shared.selectors';
import { CustomerMapping } from '../../../../core/mappings/customer.mapping';

@Component({
  selector: 'app-pay-method',
  templateUrl: './pay-method.component.html',
  styleUrls: ['./pay-method.component.scss'],
})
export class PayMethodComponent implements OnInit, OnDestroy {
  @Select(ProcessSelectors.getCurrentProcess) process$: Observable<Process>;
  @Select(SharedSelectors.getActiveCustomer) customer$: Observable<User>;
  @Input() delivery: boolean;
  @Input() pickUp: boolean;
  @Input() takeNow: boolean;
  @Input() download: boolean;
  destroy$ = new Subject();
  id = 'pay-method-modal';
  toggleMore = true;
  cartId: number;
  customer: User;

  constructor(
    private modalService: ModalService,
    private store: Store,
    private router: Router,
    private checkoutService: CheckoutService,
    private customerMap: CustomerMapping
  ) {}

  ngOnInit() {
    this.process$
      .pipe(
        filter((x) => !!x),
        takeUntil(this.destroy$)
      )
      .subscribe((process: Process) => {
        if (process) {
          this.cartId = process.cartId;
        }
      });

    this.customer$
      .pipe(
        filter((x) => !!x),
        takeUntil(this.destroy$)
      )
      .subscribe((customer: User) => {
        this.customer = customer;
      });
  }

  openDialog() {
    this.modalService.open(this.id);
  }

  closeModal() {
    this.modalService.close(this.id);
  }

  more() {
    this.toggleMore = !this.toggleMore;
  }

  confirmOrder(continueBtn: ButtonComponent) {
    if (this.customer) {
      continueBtn.startLoading();
      this.createOrder$().subscribe(() => {
        continueBtn.stopLoading();
        this.navigateToLastStep();
      });
    }
  }

  // In the future only the above will be used when we add paymet methods
  directOrder() {
    if (this.customer) {
      this.createOrder$().subscribe(() => this.navigateToLastStep());
    }
  }

  private createOrder$() {
    return this.checkoutService.createCheckout(this.cartId).pipe(
      takeUntil(this.destroy$),
      switchMap((checkout: CheckoutDTO) => {
        return this.setNotificationChannel(checkout, this.customer, this.delivery || this.download);
      }),
      switchMap((response) => {
        if (this.delivery || this.download) {
          const deliveryShippingDestionation = response.checkout.destinations.find(
            (dest: EntityDTOContainerOfDestinationDTO) => this.delivery && dest.data.target === 2
          );
          const downloadShippingDestionation = response.checkout.destinations.find(
            (dest: EntityDTOContainerOfDestinationDTO) => this.download && dest.data.target === 16
          );
          if (!deliveryShippingDestionation && !downloadShippingDestionation) {
            return forkJoin(
              this.store.dispatch(new SetPaymentTypeToCheckout(response.checkout.id, this.customer, response.delivery)),
              of({
                checkout: response.checkout,
                delivery: response.delivery,
                finished: true,
                downloadDestinationNedded: false,
                downloadDestinationDTO: undefined,
              })
            );
          }
          if (deliveryShippingDestionation && !downloadShippingDestionation) {
            return forkJoin(
              this.store.dispatch(
                new SetDestinationToCheckout(
                  response.checkout.id,
                  deliveryShippingDestionation.id,
                  this.customer,
                  deliveryShippingDestionation.data.target
                )
              ),
              of({
                checkout: response.checkout,
                delivery: response.delivery,
                finished: false,
                downloadDestinationNedded: false,
                downloadDestinationDTO: undefined,
              })
            );
          } else if (!deliveryShippingDestionation && downloadShippingDestionation) {
            return forkJoin(
              this.store.dispatch(
                new SetDestinationToCheckout(
                  response.checkout.id,
                  downloadShippingDestionation.id,
                  this.customer,
                  downloadShippingDestionation.data.target
                )
              ),
              of({
                checkout: response.checkout,
                delivery: response.delivery,
                finished: false,
                downloadDestinationNedded: false,
                downloadDestinationDTO: undefined,
              })
            );
          } else if (deliveryShippingDestionation && downloadShippingDestionation) {
            return forkJoin(
              this.store.dispatch(
                new SetDestinationToCheckout(
                  response.checkout.id,
                  deliveryShippingDestionation.id,
                  this.customer,
                  deliveryShippingDestionation.data.target
                )
              ),
              of({
                checkout: response.checkout,
                delivery: response.delivery,
                finished: false,
                downloadDestinationNedded: true,
                downloadDestinationDTO: downloadShippingDestionation.data,
              })
            );
          } else {
            return forkJoin(
              this.store.dispatch(new SetPaymentTypeToCheckout(response.checkout.id, this.customer, response.delivery)),
              of({
                checkout: response.checkout,
                delivery: response.delivery,
                finished: true,
                downloadDestinationNedded: false,
                downloadDestinationDTO: undefined,
              })
            );
          }
        } else {
          return forkJoin(
            this.store.dispatch(new SetPaymentTypeToCheckout(response.checkout.id, this.customer, response.delivery)),
            of({
              checkout: response.checkout,
              delivery: response.delivery,
              finished: true,
              downloadDestinationNedded: false,
              downloadDestinationDTO: undefined,
            })
          );
        }
      }),
      switchMap(([, data]) => {
        if (data.finished) {
          return forkJoin(
            of({}),
            of({
              checkout: data.checkout,
              delivery: data.delivery,
              finished: true,
            })
          );
        } else if (!data.finished && data.downloadDestinationNedded && !isNullOrUndefined(data.downloadDestinationDTO)) {
          return forkJoin(
            this.store.dispatch(
              new SetDestinationToCheckout(
                data.checkout.id,
                data.downloadDestinationDTO.id,
                this.customer,
                data.downloadDestinationDTO.target
              )
            ),
            of({
              checkout: data.checkout,
              delivery: data.delivery,
              finished: false,
            })
          );
        } else {
          return forkJoin(
            this.store.dispatch(new SetPaymentTypeToCheckout(data.checkout.id, this.customer, data.delivery)),
            of({
              checkout: data.checkout,
              delivery: data.delivery,
              finished: true,
            })
          );
        }
      }),
      switchMap(([, data]) => {
        if (data.finished) {
          return of({});
        } else {
          return this.store.dispatch(new SetPaymentTypeToCheckout(data.checkout.id, this.customer, data.delivery));
        }
      })
    );
  }

  private navigateToLastStep() {
    this.store.dispatch(new EmptyFinishedOrders());
    const newBread: Breadcrumb = {
      name: 'Bestellbestätigung',
      path: 'cart/confirmation',
    };

    this.store.dispatch(new AddBreadcrumb(newBread, 'checkout'));
    const currentRoute = 'cart/confirmation';
    this.store.dispatch(new ChangeCurrentRoute(currentRoute));
    this.closeModal();
    this.router.navigate([currentRoute]);
  }

  setNotificationChannel(
    checkout: CheckoutDTO,
    customer: User,
    delivery: boolean
  ): Observable<{ checkout: CheckoutDTO; customer: User; delivery: boolean }> {
    const user: User = this.store.selectSnapshot(CustomerSelectors.getCurrentProcessActiveUser);
    const notificationChannel = this.customerMap.getNotificationChannels(user);
    return this.store.dispatch(new SetNotificationChannel(checkout.id, notificationChannel)).pipe(
      map(() => {
        return { checkout, customer, delivery };
      })
    );
  }

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