import { Location } from '@angular/common';
import { HttpErrorResponse } from '@angular/common/http';
import { ChangeDetectorRef, Component, OnInit } from '@angular/core';
import { AbstractControl, FormBuilder, FormGroup, Validators } from '@angular/forms';
import { ActivatedRoute } from '@angular/router';
import { ApplicationService } from '@core/application';
import { BreadcrumbService } from '@core/breadcrumb';
import { CrmCustomerService } from '@domain/crm';
import { CountryDTO, CustomerDTO, KeyValueDTOOfStringAndString } from '@swagger/crm';
import { UiValidators } from '@ui/validators';
import { Observable } from 'rxjs';
import { first, map, switchMap } from 'rxjs/operators';
import { validateEmail } from '../../validators/email-validator';
import { genderLastNameValidator } from '../../validators/gender-b2b-validator';
import { camelCase } from 'lodash';

@Component({ template: '' })
export abstract class CustomerDataEditComponent implements OnInit {
  customer$: Observable<CustomerDTO>;
  customerId$: Observable<number>;
  countries$: Observable<CountryDTO[]>;
  customerFeatures$: Observable<KeyValueDTOOfStringAndString[]>;
  customerType$: Observable<string>;
  isWebshopOrGuest$: Observable<boolean>;
  customerFeatureB2bOrB2c$: Observable<string>;

  control: FormGroup;

  get customerId() {
    return Number(this.activatedRoute.snapshot.params['customerId']);
  }

  afterInitForm?: (control: AbstractControl) => void;

  constructor(
    private customerService: CrmCustomerService,
    private activatedRoute: ActivatedRoute,
    private fb: FormBuilder,
    private cdr: ChangeDetectorRef,
    private location: Location,
    private breadcrumb: BreadcrumbService,
    private application: ApplicationService
  ) {}

  ngOnInit() {
    this.customerId$ = this.activatedRoute.params.pipe(map((p) => Number(p['customerId'])));
    this.customer$ = this.customerId$.pipe(
      switchMap((id) => this.customerService.getCustomer(id, 2)),
      map((cr) => cr.result)
    );
    this.customerFeatures$ = this.customer$.pipe(map((customer: CustomerDTO) => Object.values(customer.features).filter((f) => f.enabled)));
    this.customerType$ = this.customerFeatures$.pipe(
      map(
        (features: KeyValueDTOOfStringAndString[]) =>
          features.find((f) => f.key === 'store' || f.key === 'webshop' || f.key === 'b2b' || f.key === 'guest')?.key
      )
    );
    this.isWebshopOrGuest$ = this.customerType$.pipe(map((type) => type === 'webshop' || type === 'guest'));
    this.customerFeatureB2bOrB2c$ = this.customerType$.pipe(map((type) => (type === 'b2b' ? 'b2b' : 'b2c')));
    this.countries$ = this.isWebshopOrGuest$.pipe(
      switchMap((webshopOrGuest) => {
        if (!webshopOrGuest) {
          return this.customerService.getCountries().pipe(map((p) => p.result));
        } else {
          return this.customerService.getCountries().pipe(
            map((p) => p.result),
            map((countries) => countries.filter((country) => country.name === 'Deutschland'))
          );
        }
      })
    );
    this.initForm();

    this.createBreadcrumb();
  }

  async createBreadcrumb() {
    const customerFeature: string = await this.customerFeatureB2bOrB2c$.pipe(first()).toPromise();
    await this.breadcrumb.addBreadcrumbIfNotExists({
      key: this.application.activatedProcessId,
      name: 'Bearbeiten',
      path: `/kunde/${this.application.activatedProcessId}/customer/${this.customerId}/edit/${customerFeature}`,
      tags: ['customer', 'edit'],
      section: 'customer',
      params: {},
    });
  }

  async initForm() {
    const { fb } = this;
    const customerDTO = await this.customer$.pipe(first()).toPromise();
    const customerType = await this.customerType$.pipe(first()).toPromise();
    const customerFeatures = await this.customerFeatures$.pipe(first()).toPromise();
    const isB2b = customerType === 'b2b';
    const isBranch = customerType === 'store';
    const isWebshop = customerType === 'webshop';
    const isCard = customerFeatures.find((feature) => feature.key === 'p4muser');

    this.control = fb.group(
      {
        gender: fb.control(customerDTO?.gender, [isBranch ? Validators.min(1) : () => null, isBranch ? Validators.required : () => null]),
        title: fb.control(customerDTO?.title),
        lastName: fb.control(customerDTO?.lastName, [Validators.required]),
        firstName: fb.control(customerDTO?.firstName, [Validators.required]),
        dateOfBirth: fb.control(customerDTO?.dateOfBirth, [isWebshop && isCard ? Validators.required : () => null, UiValidators.date]),
        communicationDetails: fb.group({
          email: fb.control(customerDTO?.communicationDetails?.email, [validateEmail]),
          phone: fb.control(customerDTO?.communicationDetails?.phone),
          mobile: fb.control(customerDTO?.communicationDetails?.mobile),
        }),
        organisation: fb.group({
          name: fb.control(customerDTO?.organisation?.name),
          vatId: fb.control(customerDTO?.organisation?.vatId),
          department: fb.control(customerDTO?.organisation?.department),
        }),
        address: fb.group({
          street: fb.control(customerDTO?.address?.street),
          streetNumber: fb.control(customerDTO?.address?.streetNumber),
          zipCode: fb.control(customerDTO?.address?.zipCode),
          city: fb.control(customerDTO?.address?.city),
          country: fb.control(customerDTO?.address?.country),
          info: fb.control(customerDTO?.address?.info),
        }),
      },
      { validators: genderLastNameValidator(isB2b) }
    );

    if (typeof this.afterInitForm === 'function') {
      this.afterInitForm.call(this, this.control);
    }

    this.control.markAllAsTouched();
    this.cdr.markForCheck();
  }

  cancel() {
    this.location.back();
  }

  async submit() {
    if (!this.control.valid || !this.control.enabled) {
      return;
    }

    this.control.disable();

    try {
      await this.customerService.patchCustomer(this.customerId, this.control.value).toPromise();
      this.location.back();
    } catch (error) {
      this.control.enable();
      if (error instanceof HttpErrorResponse) {
        if (error.error.invalidProperties) {
          const invProps = error.error.invalidProperties;
          const keys = Object.keys(invProps);
          for (const key of keys) {
            this.control.get('address')?.get(camelCase(key))?.setErrors({ validateAddress: invProps[key] });
          }
        }
      }
      console.error(error);
    }
  }
}
