import { Component, OnInit, OnDestroy, HostListener, ChangeDetectorRef, ViewChild, ViewRef } from '@angular/core';
import { FormGroup, FormBuilder, Validators, AbstractControl } from '@angular/forms';
import { Store, Select } from '@ngxs/store';
import {
  ChangeCurrentRoute,
  AddProcess,
  UpdateCustomerFormState,
  SetOnlineCustomerCreationStatus,
  ClearPartOfCustomerCreationStatus,
} from '../../../../core/store/actions/process.actions';
import { User, Address, Features, Organisation } from '../../../../core/models/user.model';
import { Router } from '@angular/router';
import { Process, CustomerFormState } from '../../../../core/models/process.model';
import { Breadcrumb } from '../../../../core/models/breadcrumb.model';
import { Observable, Subject, of } from 'rxjs';
import { AddBreadcrumb } from '../../../../core/store/actions/breadcrumb.actions';
import { AddUser, SetUserDetails } from '../../../../core/store/actions/customer.actions';
import { takeUntil, distinctUntilChanged, switchMap, map, filter, tap, debounceTime, take, catchError } from 'rxjs/operators';
import { CustomValidators } from '../../../../shared/validation/custom-validation';
import { GENDERS, TIITLES } from '../../dropdown-values';
import { ProcessSelectors } from '../../../../core/store/selectors/process.selectors';
import { SharedSelectors } from '../../../../core/store/selectors/shared.selectors';
import { EditCustomerData } from '../../../../core/models/edit-customer.model';
import { CountrySelector } from '../../../../core/store/selectors/countries.selector';
import { Country } from '../../../../core/models/country.model';
import { isoDateFromString, scrollToFirstInvalidElement, isEmptyString } from '../../../../core/utils/app.utils';
import { isNullOrUndefined } from 'util';
import { DeliveryOption } from 'apps/sales/src/app/core/models/delivery-option.model';
import { CustomerService } from 'apps/sales/src/app/core/services/customer.service';
import { AddressDTO } from '@swagger/crm';
import { ButtonComponent, SelectComponent } from '@libs/ui';
import { AppService } from 'apps/sales/src/app/core/services/app.service';
import { AddressSugestionsComponent } from '../address-sugestions/address-sugestions.component';

import { ErrorService } from 'apps/sales/src/app/core/error/component/error.service';
import { FormsSelectors } from 'apps/sales/src/app/core/store/selectors/forms.selectors';
import { SaveFormState, DeleteFormState } from 'apps/sales/src/app/core/store/actions/forms.actions';
import { USER_FORM_STATE_KEY, USER_EXTRAS_FORM_STATE_KEY, USER_ERRORS_FORM_STATE_KEY } from 'apps/sales/src/app/core/utils/app.constants';
import { AppSelectors } from 'apps/sales/src/app/core/store/selectors/app.selectors';
import { CustomerHelperService } from '../../services/customer-helper.service';

@Component({
  selector: 'app-create-customer-card',
  templateUrl: './create-customer-card.component.html',
  styleUrls: ['./create-customer-card.component.scss'],
})
export class CreateCustomerCardComponent implements OnInit, OnDestroy {
  @Select(ProcessSelectors.getProcesses) processes$: Observable<Process[]>;
  @Select(ProcessSelectors.getCurrentProcess) currentProcess$: Observable<Process>;
  @Select(SharedSelectors.getCustomerEditData) customerEditData$: Observable<EditCustomerData>;
  @Select(CountrySelector.getCountriesIterable) countries$: Observable<Country[]>;
  @Select(CountrySelector.getDeutchlandIterable) deutchland$: Observable<Country[]>;
  @ViewChild('postBtn') postBtn: ButtonComponent;
  @ViewChild('landDD') landDD: SelectComponent;
  @ViewChild('suggestions')
  suggestions: AddressSugestionsComponent;
  destroy$ = new Subject();
  destroyForm$ = new Subject();
  userForm: FormGroup;
  submitted = false;
  processes: Process[] = [];
  id: number;
  headerText = 'Wenn Sie möchten legen wir Ihnen gerne ein Onlinekonto an. Dort können Sie Ihre Bestellungen einsehen.';

  countryList: Country[];

  genders = GENDERS;
  titels = TIITLES;
  showCompanyFields = false;
  formState = '';
  customer: EditCustomerData;
  loaded = false;
  create = true;
  btnText = 'Speichern';
  canBeSetToActiveUser: boolean;
  cartHasItemsForDelivery = false;
  cartHasItemsForPickUp = false;
  cartHasItemsForTakeNow = false;
  cartHasItemsForDownload = false;
  guestChecked = false;
  onlineChecked = false;
  guestDisabled = false;
  customerCardChecked = false;
  deliveryAndGuestOrOnline = false;
  pickUpOrTakeNowAndOnline = false;
  downloadAndOnline = false;
  timer: any;
  errorTimer: any;
  firstEmailInput = false;
  isIPad = false;
  backendValidation = false;
  cityGeneralError = false;
  addressGeneralError = false;
  addressNoGeneralError = false;
  zipGeneralError = false;
  countryGeneralError = false;
  shouldValidateAddressForSimpleCustomer = false;
  lastEmailValueChecked: string;
  lastEmailCheckResult: any = null;
  flagsSetByConditions = false;
  customerFormState: CustomerFormState = CustomerFormState.CREATE;
  firstLoad = true;
  formListenerSet = false;

  addressSuggestions: Address[];
  addressFields = {
    city: true,
    address: true,
    streetNo: true,
    zipCode: true,
    country: true,
  };

  get countries() {
    return this.countries$.pipe(
      map((t) => {
        this.countryList = t;
        return t.map((i) => i.value);
      })
    );
  }

  get deutchland() {
    return this.deutchland$.pipe(
      map((t) => {
        this.countryList = t;
        return t.map((i) => i.value);
      })
    );
  }

  constructor(
    private fb: FormBuilder,
    private store: Store,
    private router: Router,
    private customerService: CustomerService,
    private cdrf: ChangeDetectorRef,
    private appService: AppService,
    private errorService: ErrorService,
    private customerHelper: CustomerHelperService
  ) {}

  ngOnInit() {
    this.isIPad = this.appService.isIPadEnv();
    this.initialize();
  }

  initialize() {
    this.store
      .select(SharedSelectors.cartHasItemsFor)
      .pipe(
        distinctUntilChanged(),
        tap(this.processTypes),
        switchMap(() => this.customerEditData$),
        filter((data) => !isNullOrUndefined(data)),
        switchMap(this.customerToProcessSwitcher),
        filter((data) => !isNullOrUndefined(data)),
        takeUntil(this.destroy$)
      )
      .subscribe(this.initializationSubscriptionHandler);

    this.store
      .select(AppSelectors.getCurrentProcessId)
      .pipe(takeUntil(this.destroy$))
      .subscribe((processId) => {
        if (!this.flagsSetByConditions) {
          this.onlineChecked = false;
          this.guestChecked = false;
          this.guestDisabled = true;
          this.deliveryAndGuestOrOnline = false;
        }
        this.loadExtrasState();
        this.loadErrorsState();
      });

    this.customerHelper.customerUpdateRedirect$.pipe(debounceTime(2000), take(1)).subscribe(() => {
      if (
        this.customerFormState === CustomerFormState.MISSING_DELIVERY ||
        (this.customerFormState === CustomerFormState.MISSING_ONLINE && this.userForm.value.first_name !== undefined)
      ) {
        this.valueChangesListenerImplementation(this.userForm.value);
        setTimeout(() => {
          this.updateFormLabelsState(null);
        }, 50);
      }
    });
  }

  isAddressField = (field: string): boolean => {
    return this.addressFields[field] !== undefined;
  };

  customerToProcessSwitcher = (customer: EditCustomerData) => {
    if (customer) {
      this.customer = customer;
    }
    return this.currentProcess$;
  };

  processTypes = (cartHasItemsFor: (option: DeliveryOption) => boolean) => {
    this.flagsSetByConditions = false;
    this.cartHasItemsForDelivery = cartHasItemsFor(DeliveryOption.DELIVERY);
    this.cartHasItemsForPickUp = cartHasItemsFor(DeliveryOption.PICK_UP);
    this.cartHasItemsForTakeNow = cartHasItemsFor(DeliveryOption.TAKE_NOW);
    this.cartHasItemsForDownload = cartHasItemsFor(DeliveryOption.DOWNLOAD);

    this.cartHasItemsForDownload.ifTrue(() => {
      this.onlineChecked = true;
      this.guestDisabled = true;
      this.guestChecked = false;
      this.flagsSetByConditions = true;

      this.headerText =
        'Um Ihnen das ebook bereitstellen zu können, brauchen Sie ein Onlinekonto bei Hugendubel. Wir richten es Ihnen gerne sofort ein.';

      return;
    });

    // Ruecklage
    if (this.cartHasItemsForTakeNow) {
      this.disableGuestCheckbox();
    }

    // Abholung
    if (this.cartHasItemsForPickUp) {
      this.disableGuestCheckbox();
    }

    // Versand
    if (this.cartHasItemsForDelivery) {
      this.guestCheckboxInitialization();
    }

    this.detectChanges();
  };

  disableGuestCheckbox = () => {
    this.guestDisabled = true;
    this.flagsSetByConditions = true;
  };

  guestCheckboxInitialization = () => {
    this.guestDisabled = false;
    this.flagsSetByConditions = true;

    if (!this.guestChecked && !this.onlineChecked) {
      this.guestChecked = true;
    }
  };

  initializationSubscriptionHandler = (process: Process) => {
    if (process) {
      this.backendValidation = false;
      clearTimeout(this.errorTimer);
      if (process.onlineCustomerCreationError && process.onlineCustomerCreationError.error === true) {
        this.buildCreateForm(this.fb);
        this.errorTimer = setTimeout(() => {
          this.onlineCustomerCreationErrorHandler(process.onlineCustomerCreationError.invalidProperties);
        }, 1000);
        this.loaded = true;
        return;
      }
      this.formState = process.customerFormState;
      this.canBeSetToActiveUser = !process.closeDirectlyTab;
      this.customerFormState = process.customerFormState;
      if (
        process.customerFormState === CustomerFormState.MISSING_DELIVERY &&
        this.customer.customer &&
        this.customer.customer.hasOnlineAccount
      ) {
        this.buildSetDeliveryAddressForm(this.fb, this.customer.customer);
        this.customerHelper.customerUpdateRedirect();
        this.id = this.customer.customer.id;
        this.submitted = true;
        this.btnText = 'Weiter';
        this.create = false;
      } else if (
        process.customerFormState === CustomerFormState.MISSING_ONLINE ||
        (process.customerFormState === CustomerFormState.MISSING_DELIVERY && !this.customer.customer.hasOnlineAccount)
      ) {
        this.buildSetDeliveryAddressForm(this.fb, this.customer.customer);
        this.customerHelper.customerUpdateRedirect();
        this.id = this.customer.customer.id;
        this.submitted = true;
        this.btnText = 'Weiter';
        this.create = true;
      } else {
        this.buildCreateForm(this.fb);
      }

      this.setValidations();
      this.setCompanyValidators();
      // scrollToFirstInvalidElement();
      this.loaded = true;

      // store user form data on changes
      this.listenFormChanges();
    }
  };

  private listenFormChanges() {
    // if (!this.formListenerSet) {
    this.destroyForm$.next();
    this.userForm.valueChanges.pipe(takeUntil(this.destroyForm$)).subscribe((v) => {
      this.valueChangesListenerImplementation(v);
    });
    //   this.formListenerSet = true;
    // }
  }

  private valueChangesListenerImplementation(v: any) {
    const formStateString = JSON.stringify(v);
    const errors = {};
    Object.keys(v).forEach((field) => {
      errors[field] = this.userForm.get(field).errors;
    });
    this.store.dispatch(new SaveFormState(USER_FORM_STATE_KEY, formStateString));
    this.store.dispatch(new SaveFormState(USER_ERRORS_FORM_STATE_KEY, JSON.stringify(errors)));
  }

  onlineCustomerCreationErrorHandler(invalidProperties: any) {
    if (isNullOrUndefined(invalidProperties) || isNullOrUndefined(this.userForm)) {
      return;
    }
    if (invalidProperties.Email) {
      this.userForm.get('email').setErrors({
        backendValidation: true,
        backendValidationMsg: invalidProperties.Email,
      });
      this.backendValidation = true;
    } else {
      this.userForm.get('email').setErrors(undefined);
    }
    if (invalidProperties.FirstName) {
      this.userForm.get('firstName').setErrors({
        backendValidation: true,
        backendValidationMsg: invalidProperties.FirstName,
      });
      this.backendValidation = true;
    } else {
      this.userForm.get('firstName').setErrors(undefined);
    }
    if (invalidProperties.LastName) {
      this.userForm.get('lastName').setErrors({
        backendValidation: true,
        backendValidationMsg: invalidProperties.LastName,
      });
      this.backendValidation = true;
    } else {
      this.userForm.get('lastName').setErrors(undefined);
    }
    let showErrorPopUp = false;
    let keysChecked = 0;
    Object.keys(invalidProperties).forEach((key) => {
      keysChecked++;
      if (key !== 'Email' && key !== 'FirstName' && key !== 'LastName') {
        showErrorPopUp = true;
      }
      if (keysChecked === Object.keys(invalidProperties).length && showErrorPopUp) {
        this.errorService.addErrors(400, null, JSON.stringify(invalidProperties));
      }
    });
    scrollToFirstInvalidElement();

    this.listenFormChanges();
  }

  setValidations() {
    this.deliveryAndGuestOrOnline = this.cartHasItemsForDelivery && (this.guestChecked || this.onlineChecked);
    this.pickUpOrTakeNowAndOnline =
      (this.cartHasItemsForPickUp || this.cartHasItemsForTakeNow) && this.onlineChecked && !this.deliveryAndGuestOrOnline;
    this.downloadAndOnline = this.cartHasItemsForDownload && this.onlineChecked;
    (
      this.deliveryAndGuestOrOnline ||
      this.pickUpOrTakeNowAndOnline ||
      this.downloadAndOnline ||
      this.onlineChecked ||
      this.guestChecked
    ).ifTrue(this.deliveryAndGuestValidationsOrpickUpOrTakeNowAndOnlineValidations);
    this.onlineChecked.ifTrue(this.onlineExtraValidations);
  }

  deliveryAndGuestValidationsOrpickUpOrTakeNowAndOnlineValidations = () => {
    this.userForm.get('gender').setValidators([Validators.required, CustomValidators.validateGender]);
    this.userForm.get('gender').updateValueAndValidity();
    this.userForm.get('email').setValidators([Validators.required, CustomValidators.validateEmail]);
    this.userForm.get('email').updateValueAndValidity();
    this.userForm.get('address').setValidators([Validators.required]);
    this.userForm.get('address').updateValueAndValidity();
    this.userForm.get('streetNo').setValidators([Validators.required]);
    this.userForm.get('streetNo').updateValueAndValidity();
    this.userForm.get('zipCode').setValidators([Validators.required]);
    this.userForm.get('zipCode').updateValueAndValidity();
    this.userForm.get('city').setValidators([Validators.required]);
    this.userForm.get('city').updateValueAndValidity();
    this.userForm.get('country').setValidators([Validators.required]);
    this.userForm.get('country').updateValueAndValidity();
  };

  addressValidatorForSimpleCustomer = (data: any) => {
    if (data) {
      const street = data.address as string;
      const streetNo = data.streetNo as string;
      const zipCode = data.zipCode as string;
      const city = data.city as string;
      const countryValue = data.country as string;
      if (
        !isEmptyString(street) ||
        !isEmptyString(streetNo) ||
        !isEmptyString(zipCode) ||
        !isEmptyString(city) ||
        !isEmptyString(countryValue)
      ) {
        this.userForm.get('address').setValidators([Validators.required]);
        this.userForm.get('streetNo').setValidators([Validators.required]);
        this.userForm.get('zipCode').setValidators([Validators.required]);
        this.userForm.get('city').setValidators([Validators.required]);
        this.userForm.get('country').setValidators([Validators.required]);
        this.shouldValidateAddressForSimpleCustomer = true;
      } else {
        this.userForm.get('address').clearValidators();
        this.userForm.get('streetNo').clearValidators();
        this.userForm.get('zipCode').clearValidators();
        this.userForm.get('city').clearValidators();
        this.userForm.get('country').clearValidators();
        this.shouldValidateAddressForSimpleCustomer = false;
      }
      this.userForm.get('address').updateValueAndValidity();
      this.userForm.get('streetNo').updateValueAndValidity();
      this.userForm.get('zipCode').updateValueAndValidity();
      this.userForm.get('city').updateValueAndValidity();
      this.userForm.get('country').updateValueAndValidity();
    }
  };

  onlineExtraValidations = () => {
    this.userForm.get('email').setAsyncValidators(this.validateIfEmailExists.bind(this));
    this.userForm.get('email').updateValueAndValidity();
  };

  resetValidations = () => {
    this.userForm.get('gender').clearValidators();
    this.userForm.get('gender').updateValueAndValidity();
    this.userForm.get('email').clearAsyncValidators();
    this.userForm.get('email').setValidators([CustomValidators.validateEmail]);
    this.userForm.get('email').updateValueAndValidity();
    this.userForm.get('address').clearValidators();
    this.userForm.get('address').updateValueAndValidity();
    this.userForm.get('streetNo').clearValidators();
    this.userForm.get('streetNo').updateValueAndValidity();
    this.userForm.get('zipCode').clearValidators();
    this.userForm.get('zipCode').updateValueAndValidity();
    this.userForm.get('city').clearValidators();
    this.userForm.get('city').updateValueAndValidity();
    this.userForm.get('country').clearValidators();
    this.userForm.get('country').updateValueAndValidity();
    this.deliveryAndGuestOrOnline = this.cartHasItemsForDelivery && (this.guestChecked || this.onlineChecked);
    this.pickUpOrTakeNowAndOnline = (this.cartHasItemsForPickUp || this.cartHasItemsForTakeNow) && this.onlineChecked;
  };

  validateIfEmailExists(control: AbstractControl) {
    return control.value ? this.emailValidation$(control.value) : of(null);
  }

  emailValidation$ = (value: string) => {
    if (value === this.lastEmailValueChecked) {
      return of(this.lastEmailCheckResult);
    }
    clearTimeout(this.timer);
    const result$ = new Subject<any>();
    this.timer = setTimeout(() => {
      this.customerService
        .emailExists(value)
        .pipe(
          take(1),
          map((exists: Boolean) => {
            if (isNullOrUndefined(exists)) {
              return { invalidEmail: true };
            }
            return exists ? { emailExists: true } : null;
          })
        )
        .subscribe((result) => {
          this.lastEmailValueChecked = value;
          this.lastEmailCheckResult = result;
          const errors = {};
          Object.keys(this.userForm.controls).forEach((field) => {
            if (field === 'email') {
              errors[field] = result;
            } else {
              errors[field] = this.userForm.get(field).errors;
            }
          });
          this.store.dispatch(new SaveFormState(USER_ERRORS_FORM_STATE_KEY, JSON.stringify(errors)));
          result$.next(result);
        });
    }, 2000);
    return result$;
  };

  async validateAddress() {
    const street = this.userForm.get('address').value as string;
    const streetNo = this.userForm.get('streetNo').value as string;
    const zipCode = this.userForm.get('zipCode').value as string;
    const city = this.userForm.get('city').value as string;
    const countryValue = this.userForm.get('country').value as string;
    let countryCode: string;
    if (countryValue) {
      const country = this.countryList.find((cl) => cl.value === countryValue);
      if (country) {
        countryCode = country.key;
      }
    }

    const address = <AddressDTO>{
      street: street,
      streetNumber: streetNo,
      zipCode: zipCode,
      city: city,
      country: countryCode,
    };
    return await this.customerService.addressValid(address).toPromise();
  }

  async post(ignoreSuggestions = false) {
    this.postBtn.startLoading();
    if (
      (this.pickUpOrTakeNowAndOnline ||
        this.deliveryAndGuestOrOnline ||
        this.onlineChecked ||
        this.guestChecked ||
        this.shouldValidateAddressForSimpleCustomer) &&
      this.userForm.valid
    ) {
      const addressResponse = await this.validateAddress();
      if (addressResponse && addressResponse.invalidProperties) {
        this.invalidAddressMapping(addressResponse.invalidProperties);
        this.postBtn.stopLoading();
      } else if (ignoreSuggestions) {
        this.createUser();
      } else {
        this.setAddressSuggestions(addressResponse);
      }
    } else {
      this.createUser();
    }
  }

  createUser() {
    if (this.userForm.valid) {
      this.createProcessIfDosntExists();
      if (this.create) {
        this.createNewCustomer();
      } else {
        this.backToCart();
      }
    } else {
      this.postBtn.stopLoading();
      this.submitted = true;
      this.saveStateExtras();
      scrollToFirstInvalidElement();
    }
  }

  setAddressSuggestions(address: any) {
    this.addressSuggestions = [];
    if (address && Array.isArray(address) && address.length > 0) {
      const firstName = this.userForm.get('firstName').value;
      const lastName = this.userForm.get('lastName').value;
      let processedItems = 0;
      const addressesLength = address.length;
      address.forEach((add) => {
        processedItems++;
        const street = add.street ? add.street : (this.userForm.get('address').value as string);
        const streetNo = add.streetNumber ? add.streetNumber : (this.userForm.get('streetNo').value as string);
        const zipCode = add.zipCode ? add.zipCode : (this.userForm.get('zipCode').value as string);
        const city = add.city ? add.city : (this.userForm.get('city').value as string);
        const countryValue = add.country ? add.country : (this.userForm.get('country').value as string);

        if (city && street && streetNo && zipCode && countryValue) {
          this.addressSuggestions.push({
            id: 0,
            first_name: firstName as string,
            last_name: lastName as string,
            country: countryValue as string,
            city: city as string,
            street: street as string,
            streetNo: streetNo as number,
            zip: zipCode,
          });
        }
        if (processedItems === addressesLength && this.addressSuggestions.length === addressesLength) {
          this.openSuggestions();
        }
      });
    } else {
      this.createUser();
    }
  }

  updateValuesOfAddress(add: Address) {
    if (add.city) {
      this.userForm.get('city').setValue(add.city);
      this.cityGeneralError = false;
    }
    if (add.street) {
      this.userForm.get('address').setValue(add.street);
      this.addressGeneralError = false;
    }
    if (add.streetNo) {
      this.userForm.get('streetNo').setValue(add.streetNo);
      this.addressNoGeneralError = false;
    }
    if (add.zip) {
      this.userForm.get('zipCode').setValue(add.zip);
      this.zipGeneralError = false;
    }
    if (add.country) {
      this.userForm.get('country').setValue(add.country);
    }
  }

  invalidAddressMapping(invalid: any) {
    if (invalid.City) {
      this.userForm.get('city').setErrors({
        backendValidation: true,
        backendValidationMsg: invalid.City,
      });
      this.submitted = true;
    }
    if (invalid.Street) {
      this.userForm.get('address').setErrors({
        backendValidation: true,
        backendValidationMsg: invalid.Street,
      });
      this.submitted = true;
    }
    if (invalid.streetNumber) {
      this.userForm.get('streetNo').setErrors({
        backendValidation: true,
        backendValidationMsg: invalid.streetNumber,
      });
      this.submitted = true;
    }
    if (invalid.ZipCode) {
      this.userForm.get('zipCode').setErrors({
        backendValidation: true,
        backendValidationMsg: invalid.ZipCode,
      });
      this.submitted = true;
    }
    if (invalid.Country) {
      this.userForm.get('country').setErrors({
        backendValidation: true,
        backendValidationMsg: invalid.Country,
      });
      this.submitted = true;
    }
    if (invalid.General) {
      this.cityGeneralError = true;
      this.addressGeneralError = true;
      this.addressNoGeneralError = true;
      this.zipGeneralError = true;
      this.countryGeneralError = true;
      this.submitted = true;
    }
    scrollToFirstInvalidElement();
  }

  private createNewCustomer() {
    const data = this.createUserData();

    this.store
      .dispatch(new AddUser(data, this.canBeSetToActiveUser))
      .pipe(
        switchMap(() => {
          return this.store.select(ProcessSelectors.getDetailsUserId);
        }),
        take(1),
        catchError((error) => {
          this.postBtn.stopLoading();
          scrollToFirstInvalidElement();
          return of(undefined);
        })
      )
      .subscribe((newCustomerId) => {
        if (newCustomerId) {
          const currentRoute = 'customer/edit/' + newCustomerId;
          this.router.navigate([currentRoute]);
          this.store.dispatch(new ChangeCurrentRoute(currentRoute));
          // unset user form data in store
          this.store.dispatch(new DeleteFormState(USER_FORM_STATE_KEY));
          this.store.dispatch(new DeleteFormState(USER_EXTRAS_FORM_STATE_KEY));
          this.store.dispatch(new DeleteFormState(USER_ERRORS_FORM_STATE_KEY));
          this.store.dispatch(
            new SetOnlineCustomerCreationStatus({
              error: false,
              invalidProperties: null,
            })
          );
        }
        this.postBtn.stopLoading();
      });
  }

  private backToCart() {
    const data = this.createUserData();
    const newBread: Breadcrumb = {
      name: 'Warenkorb',
      path: 'cart/review',
    };

    this.store.dispatch(new AddBreadcrumb(newBread, 'shoppingCart'));
    this.store
      .dispatch(new SetUserDetails(data, false))
      .toPromise()
      .then(() => {
        const currentRoute = 'cart/review';
        this.store.dispatch(new UpdateCustomerFormState(CustomerFormState.CREATE));
        this.store.dispatch(new ChangeCurrentRoute(currentRoute));
        this.postBtn.stopLoading();
        this.router.navigate([currentRoute]);
      });
  }

  loadProcesses() {
    this.processes$.pipe(takeUntil(this.destroy$)).subscribe((data: Process[]) => {
      this.processes = data;
    });
  }

  createProcess() {
    const newProcess = <Process>{
      id: 1,
      name: 'Vorgang 1',
      currentRoute: '/product/search',
    };

    this.store.dispatch(new AddProcess(newProcess));
    this.store.dispatch(
      new AddBreadcrumb(
        <Breadcrumb>{
          name: 'Artikelsuche',
          path: '/product/search',
        },
        'shoppingCart'
      )
    );
  }

  createProcessIfDosntExists() {
    this.loadProcesses();
    if (this.processes.length === 0) {
      this.createProcess();
    }
  }

  setCompanyValidators() {
    this.userForm
      .get('company')
      .valueChanges.pipe(distinctUntilChanged(), takeUntil(this.destroy$))
      .subscribe((companyName: string) => {
        if (companyName) {
          this.showCompanyFields = true;
        } else {
          this.showCompanyFields = false;
        }
      });
  }

  setAddressValidators = () => {
    this.userForm.valueChanges.pipe(distinctUntilChanged(), take(1)).subscribe(this.addressValidatorForSimpleCustomer);
  };

  get f() {
    return this.userForm.controls;
  }

  valueChanges(control: AbstractControl, value: string, field?: string) {
    if (field === 'email') {
      value = value.trim();
    }
    this.isAddressField(field).ifTrue(this.setAddressValidators);
    this.updateGeneralAddressErrors(field);
    control.setValue(value);
  }

  clearErrors(field: string) {
    this.userForm.get(field).setErrors(undefined);
    this.clearBackednApiErrorsFromStore(field);
  }

  clearBackednApiErrorsFromStore(field: string) {
    let key;
    if (field === 'firstName') {
      key = 'FirstName';
    }
    if (field === 'lastName') {
      key = 'LastName';
    }
    if (field === 'email') {
      key = 'Email';
    }
    if (field === 'city') {
      key = 'City';
    }
    if (field === 'streetNo') {
      key = 'streetNumber';
    }
    if (field === 'zipCode') {
      key = 'ZipCode';
    }
    if (field === 'address') {
      key = 'Street';
    }
    if (field === 'country') {
      key = 'Country';
    }
    if (key) {
      this.store.dispatch(new ClearPartOfCustomerCreationStatus(key));
    }
  }

  updateGeneralAddressErrors(field: string) {
    (field === 'city').ifTrue(() => (this.cityGeneralError = false));
    (field === 'zipCode').ifTrue(() => (this.zipGeneralError = false));
    (field === 'streetNo').ifTrue(() => (this.addressNoGeneralError = false));
    (field === 'address').ifTrue(() => (this.addressGeneralError = false));
  }

  firstEmailChange() {
    const emailInput = this.userForm.get('email').value;
    if (!isNullOrUndefined(emailInput) && emailInput !== '') {
      this.firstEmailInput = true;
    } else {
      this.firstEmailInput = false;
    }
  }

  genderSelect(gender: string) {
    this.updateDataForSelectedOption('gender', gender, 'Andrede');
  }

  titelSelect(title: string) {
    this.updateDataForSelectedOption('title', title, 'Titel');
  }

  countrySelect(country: string) {
    this.updateDataForSelectedOption('country', country, 'Land');
    this.setAddressValidators();
  }

  private createUserData(): User {
    const address = new Address(
      null,
      this.userForm.get('firstName').value,
      this.userForm.get('lastName').value,
      this.userForm.get('address').value ? this.userForm.get('address').value : '',
      this.userForm.get('streetNo').value ? this.userForm.get('streetNo').value : '',
      +this.userForm.get('zipCode').value ? this.userForm.get('zipCode').value : '',
      this.userForm.get('city').value ? this.userForm.get('city').value : '',
      this.userForm.get('country').value ? this.getCountryCode(this.userForm.get('country').value) : '',
      this.userForm.get('company').value ? this.userForm.get('company').value : '',
      this.userForm.get('department').value ? this.userForm.get('department').value : '',
      this.userForm.get('note').value ? this.userForm.get('note').value : '',
      this.userForm.get('tax_number').value ? this.userForm.get('tax_number').value : '',
      this.userForm.get('title').value ? this.userForm.get('title').value : '',
      this.userForm.get('gender').value ? this.userForm.get('gender').value : ''
    );

    const features: Features[] = [];
    if (this.guestChecked) {
      features.push({
        key: 'guestaccount',
        value: undefined,
        description: 'Gastkunde',
      });
    }
    if (this.onlineChecked) {
      features.push({
        key: 'onlineshop',
        value: undefined,
        description: 'Onlineshop',
      });
    }
    if (this.customerCardChecked) {
      features.push({
        key: 'p4mUser',
        value: undefined,
        description: 'Kundenkarte',
      });
    }

    let organisation: Organisation;
    if (this.showCompanyFields) {
      organisation = {
        name: this.userForm.get('company').value ? this.userForm.get('company').value : undefined,
        department: this.userForm.get('department').value ? this.userForm.get('department').value : undefined,
        extraAddress: this.userForm.get('note').value ? this.userForm.get('note').value : undefined,
        vatId: this.userForm.get('tax_number').value ? this.userForm.get('tax_number').value : undefined,
      };
    }

    const data: User = {
      id: this.id,
      first_name: this.userForm.get('firstName').value,
      last_name: this.userForm.get('lastName').value,
      title: this.userForm.get('title').value ? this.userForm.get('title').value : '',
      gender: this.userForm.get('gender').value ? this.userForm.get('gender').value : '',
      mobile_number: this.userForm.get('mobile').value ? this.userForm.get('mobile').value.replace(' ', '') : '',
      phone_number: this.userForm.get('telephone').value ? this.userForm.get('telephone').value.replace(' ', '') : '',
      date_of_birth: isoDateFromString(this.userForm.get('dateOfBirth').value),
      delivery_addres: address,
      poossible_invoice_addresses: [address],
      invoice_address: address,
      poossible_delivery_addresses: [address],
      email: this.userForm.get('email').value ? this.userForm.get('email').value.trim() : '',
      shop: Math.floor(Math.random() * 6) + 1 > 3 ? true : false,
      newUser: true,
      features: features,
      organisation: organisation,
    };

    return data;
  }

  private updateDataForSelectedOption(field: string, value: string, defaultValue: string) {
    if (value !== defaultValue) {
      this.userForm.get(field).patchValue(value);
    } else {
      this.userForm.get(field).patchValue(null);
    }
  }

  private buildSetDeliveryAddressForm(fb: FormBuilder, customer: User) {
    this.store
      .selectOnce(FormsSelectors.getFormState)
      .pipe(map((filterFn) => filterFn(USER_FORM_STATE_KEY)))
      .subscribe((value) => {
        if (this.customerFormState === CustomerFormState.MISSING_DELIVERY || this.customerFormState === CustomerFormState.MISSING_ONLINE) {
          let data;
          if (this.firstLoad) {
            data = customer;
          } else {
            data = value ? JSON.parse(value) : undefined;
          }
          let country = this.getProperty(data, this.firstLoad ? 'delivery_addres.country' : 'country');
          const countriesList = this.store.selectSnapshot(CountrySelector.getCountriesIterable);
          if (countriesList) {
            const countryObj = countriesList.find((c) => c.key === country);
            if (countryObj !== undefined) {
              country = countryObj.value;
            }
          }
          this.userForm = fb.group({
            firstName: [this.getProperty(data, this.firstLoad ? 'first_name' : 'firstName'), Validators.required],
            lastName: [this.getProperty(data, this.firstLoad ? 'last_name' : 'lastName'), Validators.required],
            email: [this.getProperty(data, 'email'), [CustomValidators.validateEmail, Validators.required]],
            address: [this.getProperty(data, this.firstLoad ? 'delivery_addres.street' : 'address'), Validators.required],
            streetNo: [this.getProperty(data, this.firstLoad ? 'delivery_addres.streetNo' : 'streetNo'), Validators.required],
            zipCode: [this.getProperty(data, this.firstLoad ? 'delivery_addres.zip' : 'zipCode'), Validators.required],
            city: [this.getProperty(data, this.firstLoad ? 'delivery_addres.city' : 'city'), Validators.required],
            dateOfBirth: [this.getProperty(data, this.firstLoad ? 'date_of_birth' : 'dateOfBirth'), CustomValidators.validateDateOfBirth],
            mobile: [this.getProperty(data, this.firstLoad ? 'mobile_number' : 'mobile'), CustomValidators.validateTelephone],
            telephone: [this.getProperty(data, this.firstLoad ? 'phone_number' : 'telephone'), CustomValidators.validateTelephone],
            country: [country, Validators.required],
            gender: [this.getProperty(data, 'gender')],
            title: [this.getProperty(data, 'title')],
            company: [this.getProperty(data, this.firstLoad ? 'delivery_addres.company_name' : 'company')],
            department: [this.getProperty(data, this.firstLoad ? 'delivery_addres.company_department' : 'department')],
            tax_number: [this.getProperty(data, this.firstLoad ? 'delivery_addres.company_tax_number' : 'tax_number')],
            note: [this.getProperty(data, this.firstLoad ? 'delivery_addres.note' : 'note')],
          });

          if (this.firstLoad) {
            this.valueChangesListenerImplementation(this.userForm.value);
            this.firstLoad = false;
          }
          setTimeout(() => {
            this.updateFormLabelsState(null);
          }, 50);
        }
      });
  }

  private buildCreateForm(fb: FormBuilder) {
    this.store
      .selectOnce(FormsSelectors.getFormState)
      .pipe(map((filterFn) => filterFn(USER_FORM_STATE_KEY)))
      .subscribe((value) => {
        if (this.customerFormState === CustomerFormState.CREATE) {
          const data = value ? JSON.parse(value) : undefined;
          this.userForm = fb.group({
            firstName: [this.getProperty(data, 'firstName') || '', Validators.required],
            lastName: [this.getProperty(data, 'lastName') || '', Validators.required],
            email: [this.getProperty(data, 'email') || '', CustomValidators.validateEmail],
            address: [this.getProperty(data, 'address') || ''],
            streetNo: [this.getProperty(data, 'streetNo') || ''],
            zipCode: [this.getProperty(data, 'zipCode') || ''],
            city: [this.getProperty(data, 'city') || ''],
            dateOfBirth: [this.getProperty(data, 'dateOfBirth') || '', CustomValidators.validateDateOfBirth],
            mobile: [this.getProperty(data, 'mobile') || '', CustomValidators.validateTelephone],
            telephone: [this.getProperty(data, 'telephone') || '', CustomValidators.validateTelephone],
            country: [this.getProperty(data, 'country') || ''],
            gender: [this.getProperty(data, 'gender') || ''],
            title: [this.getProperty(data, 'title') || ''],
            company: [this.getProperty(data, 'company') || ''],
            department: [this.getProperty(data, 'department') || ''],
            tax_number: [this.getProperty(data, 'tax_number') || ''],
            note: [this.getProperty(data, 'note') || ''],
          });
          setTimeout(() => {
            this.updateFormLabelsState(data);
          }, 50);
        }
      });
  }

  private updateFormLabelsState(data: any) {
    this.updateFieldState('firstName');
    this.updateFieldState('lastName');
    this.updateFieldState('email');
    this.updateFieldState('address');
    this.updateFieldState('streetNo');
    this.updateFieldState('zipCode');
    this.updateFieldState('city');
    this.updateFieldState('dateOfBirth');
    this.updateFieldState('mobile');
    this.updateFieldState('telephone');
    this.updateFieldState('country');
    this.updateFieldState('gender');
    this.updateFieldState('title');
    this.updateFieldState('company');
    this.updateFieldState('department');
    this.updateFieldState('tax_number');
    this.updateFieldState('note');
  }

  private updateFieldState(field: any) {
    if (field) {
      if (this.userForm.get(field) && this.userForm.get(field).value && this.userForm.get(field).value.length > 0) {
        this.userForm.get(field).markAsDirty();
      } else {
        this.userForm.get(field).markAsUntouched();
      }
    }
  }

  private loadExtrasState() {
    const value = this.store.selectSnapshot(FormsSelectors.getFormState)(USER_EXTRAS_FORM_STATE_KEY);
    const data = value ? JSON.parse(value) : undefined;
    const guest = data ? (this.getProperty(data, 'guest') as boolean) : undefined;
    const online = data ? (this.getProperty(data, 'online') as boolean) : undefined;
    const submitted = data ? (this.getProperty(data, 'submitted') as boolean) : undefined;
    const guestDisabled = data ? (this.getProperty(data, 'guestDisabled') as boolean) : undefined;
    setTimeout(() => {
      if (guest !== this.guestChecked && !isNullOrUndefined(guest)) {
        this.toggleGuest(false);
      }
      if (online !== this.onlineChecked && !isNullOrUndefined(online)) {
        this.toggleOnline(false);
      }
      if (submitted !== this.submitted && !isNullOrUndefined(submitted)) {
        this.submitted = submitted;
      } else {
        this.submitted = false;
      }
      if (guestDisabled !== this.guestDisabled && !isNullOrUndefined(guestDisabled)) {
        this.guestDisabled = guestDisabled;
      }
    }, 400);
  }

  private loadErrorsState() {
    const value = this.store.selectSnapshot(FormsSelectors.getFormState)(USER_ERRORS_FORM_STATE_KEY);
    if (value) {
      const data = JSON.parse(value);
      setTimeout(() => {
        Object.keys(this.userForm.controls).forEach((key) => {
          if (data[key]) {
            this.userForm.get(key).setErrors(data[key]);
          } else {
            this.userForm.get(key).setErrors(undefined);
          }
        });
      }, 400);
    }
  }

  getProperty(obj: Object, key: string) {
    return key.split('.').reduce((o, x) => {
      return typeof o === 'undefined' || o === null ? o : o[x];
    }, obj);
  }

  getCountryCode(name: string) {
    return this.countryList.find((t) => t.value === name).key;
  }

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

  toggle(checkbox: string) {
    if (checkbox === 'guestChecked' && this.guestDisabled) {
      return;
    }
    this[checkbox] = !this[checkbox];
    const type = this[checkbox] as boolean;
    if (type) {
      this.setValidations();
    } else {
      this.resetValidations();
    }
  }

  toggleGuest(saveState = true) {
    if (this.guestDisabled) {
      return;
    }
    if (this.cartHasItemsForDelivery && this.guestChecked && !this.onlineChecked) {
      return;
    }
    this.guestChecked = !this.guestChecked;
    if (this.guestChecked) {
      this.landDD.change('Deutschland');
      this.countrySelect('Deutschland');
      this.setValidations();
      this.onlineChecked = false;
    } else {
      this.landDD.clear('Land');
      this.countrySelect(undefined);
      this.resetValidations();
    }
    if (saveState) {
      this.saveStateExtras();
    }
  }

  toggleOnline(saveState = true) {
    if (this.cartHasItemsForDelivery && !this.guestChecked && this.onlineChecked) {
      return;
    }
    if (this.onlineChecked && this.cartHasItemsForDownload) {
      return;
    }
    this.onlineChecked = !this.onlineChecked;
    if (this.onlineChecked) {
      this.landDD.change('Deutschland');
      this.countrySelect('Deutschland');
      this.setValidations();
      this.guestChecked = false;
    } else {
      this.landDD.clear('Land');
      this.countrySelect(undefined);
      this.resetValidations();
    }
    if (saveState) {
      this.saveStateExtras();
    }
  }

  openSuggestions() {
    if (this.addressSuggestions && this.addressSuggestions.length > 0) {
      this.detectChanges();
      this.suggestions.openDialog();
    }
    this.postBtn.stopLoading();
  }

  select(address: Address) {
    this.updateValuesOfAddress(address);
    this.post(true);
  }

  ignoreSuggestions() {
    this.post(true);
  }

  private saveStateExtras() {
    this.store.dispatch(
      new SaveFormState(
        USER_EXTRAS_FORM_STATE_KEY,
        JSON.stringify({
          guest: this.guestChecked,
          online: this.onlineChecked,
          submitted: this.submitted,
          guestDisabled: this.guestDisabled,
        })
      )
    );
  }

  @HostListener('window:scroll', ['$event'])
  scrollHandler(event) {
    if (event.target.id === 'customer-form') {
      document.activeElement['blur'].apply(document.activeElement);
    }
  }

  detectChanges() {
    setTimeout(() => {
      if (this.cdrf !== null && this.cdrf !== undefined && !(this.cdrf as ViewRef).destroyed) {
        this.cdrf.detectChanges();
      }
    }, 0);
  }
}
