import { Injectable } from '@angular/core';
import { UntypedFormGroup } from '@angular/forms';
import { ApplicationService } from '@core/application';
import { DomainCheckoutService } from '@domain/checkout';
import { ComponentStore } from '@ngrx/component-store';
import { tapResponse } from '@ngrx/operators';

import {
  NotificationChannel,
  PayerDTO,
  ShoppingCartDTO,
  ShoppingCartItemDTO,
} from '@generated/swagger/checkout-api';
import { UiErrorModalComponent, UiModalService } from '@ui/modal';
import { BehaviorSubject, Subject } from 'rxjs';
import {
  first,
  map,
  switchMap,
  takeUntil,
  tap,
  withLatestFrom,
} from 'rxjs/operators';

export interface CheckoutReviewState {
  payer: PayerDTO;
  shoppingCart: ShoppingCartDTO;
  shoppingCartItems: ShoppingCartItemDTO[];
  fetching: boolean;
}

@Injectable()
export class CheckoutReviewStore extends ComponentStore<CheckoutReviewState> {
  orderCompleted = new Subject<void>();

  get shoppingCart() {
    return this.get((s) => s.shoppingCart);
  }
  set shoppingCart(shoppingCart: ShoppingCartDTO) {
    this.patchState({ shoppingCart });
  }
  readonly shoppingCart$ = this.select((s) => s.shoppingCart);

  get shoppingCartItems() {
    return this.get((s) => s.shoppingCartItems);
  }
  set shoppingCartItems(shoppingCartItems: ShoppingCartItemDTO[]) {
    this.patchState({ shoppingCartItems });
  }
  readonly shoppingCartItems$ = this.select((s) => s.shoppingCartItems);

  get fetching() {
    return this.get((s) => s.fetching);
  }
  set fetching(fetching: boolean) {
    this.patchState({ fetching });
  }
  readonly fetching$ = this.select((s) => s.fetching);

  customerFeatures$ = this._application.activatedProcessId$.pipe(
    takeUntil(this.orderCompleted),
    switchMap((processId) =>
      this._domainCheckoutService.getCustomerFeatures({ processId }),
    ),
  );

  payer$ = this._application.activatedProcessId$.pipe(
    takeUntil(this.orderCompleted),
    switchMap((processId) =>
      this._domainCheckoutService.getPayer({ processId }),
    ),
  );

  buyer$ = this._application.activatedProcessId$.pipe(
    takeUntil(this.orderCompleted),
    switchMap((processId) =>
      this._domainCheckoutService.getBuyer({ processId }),
    ),
  );

  showBillingAddress$ = this.shoppingCartItems$.pipe(
    withLatestFrom(this.customerFeatures$),
    map(
      ([items, customerFeatures]) =>
        items.some(
          (item) =>
            item.features?.orderType === 'Versand' ||
            item.features?.orderType === 'B2B-Versand' ||
            item.features?.orderType === 'DIG-Versand',
        ) || !!customerFeatures?.b2b,
    ),
  );

  checkNotificationChannelControl$ = new BehaviorSubject<boolean>(true);

  notificationChannelLoading$ = new Subject<boolean>();

  notificationsControl: UntypedFormGroup;

  constructor(
    private _domainCheckoutService: DomainCheckoutService,
    private _application: ApplicationService,
    private _uiModal: UiModalService,
  ) {
    super({
      payer: undefined,
      shoppingCart: undefined,
      shoppingCartItems: [],
      fetching: false,
    });
  }

  loadShoppingCart = this.effect(($) =>
    $.pipe(
      tap(() => (this.fetching = true)),
      withLatestFrom(this._application.activatedProcessId$),
      switchMap(([_, processId]) => {
        return this._domainCheckoutService
          .getShoppingCart({ processId, latest: true })
          .pipe(
            tapResponse(
              (shoppingCart) => {
                console.log('Loaded shopping cart', { shoppingCart });
                const shoppingCartItems =
                  shoppingCart?.items?.map((item) => item.data) || [];
                this.patchState({
                  shoppingCart,
                  shoppingCartItems,
                });
              },
              (err) => {},
              () => {},
            ),
          );
      }),
      tap(() => (this.fetching = false)),
    ),
  );

  async onNotificationChange(notificationChannels?: NotificationChannel[]) {
    this.notificationChannelLoading$.next(true);

    try {
      const control = this.notificationsControl?.getRawValue();
      const notificationChannel = notificationChannels
        ? (notificationChannels.reduce(
            (val, current) => val | current,
            0,
          ) as NotificationChannel)
        : control?.notificationChannel?.selected || 0;
      const processId = await this._application.activatedProcessId$
        .pipe(first())
        .toPromise();
      const email = control?.notificationChannel?.email;
      const mobile = control?.notificationChannel?.mobile;

      // Check if E-Mail and Mobilnumber is available if E-Mail or SMS checkbox is active
      if (notificationChannel === 3 && (!email || !mobile)) {
        this.checkNotificationChannelControl$.next(false);
      } else if (notificationChannel === 2 && !mobile) {
        this.checkNotificationChannelControl$.next(false);
      } else if (notificationChannel === 1 && !email) {
        this.checkNotificationChannelControl$.next(false);
      } else {
        this.checkNotificationChannelControl$.next(true);
      }

      // NotificationChannel nur speichern, wenn Haken und Value gesetzt
      let setNotificationChannel = 0;
      if ((notificationChannel & 1) === 1 && email) {
        setNotificationChannel += 1;
      }
      if ((notificationChannel & 2) === 2 && mobile) {
        setNotificationChannel += 2;
      }

      if (notificationChannel > 0) {
        this.setCommunicationDetails({
          processId,
          notificationChannel,
          email,
          mobile,
        });
      }
      this._domainCheckoutService.setNotificationChannels({
        processId,
        notificationChannels:
          (setNotificationChannel as NotificationChannel) || 0,
      });
    } catch (error) {
      this._uiModal.open({
        content: UiErrorModalComponent,
        data: error,
        title: 'Fehler beim setzen des Benachrichtigungskanals',
      });
    }

    this.notificationChannelLoading$.next(false);
  }

  setCommunicationDetails({
    processId,
    notificationChannel,
    email,
    mobile,
  }: {
    processId: number;
    notificationChannel: number;
    email: string;
    mobile: string;
  }) {
    const emailValid = this.notificationsControl
      ?.get('notificationChannel')
      ?.get('email')?.valid;
    const mobileValid = this.notificationsControl
      ?.get('notificationChannel')
      ?.get('mobile')?.valid;

    if (notificationChannel === 3 && emailValid && mobileValid) {
      this._domainCheckoutService.setBuyerCommunicationDetails({
        processId,
        email,
        mobile,
      });
    } else if (notificationChannel === 1 && emailValid) {
      this._domainCheckoutService.setBuyerCommunicationDetails({
        processId,
        email,
      });
    } else if (notificationChannel === 2 && mobileValid) {
      this._domainCheckoutService.setBuyerCommunicationDetails({
        processId,
        mobile,
      });
    }
  }
}
