import {
  Component,
  ChangeDetectionStrategy,
  ViewChild,
  ElementRef,
  Self,
  AfterViewInit,
  ChangeDetectorRef,
  Input,
} from '@angular/core';
import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, ValidatorFn } from '@angular/forms';
import { FormBlock, FormBlockGroup } from '../form-block';
import { DeviatingAddressFormBlockData } from './deviating-address-form-block-data';
import { NameFormBlockComponent } from '../name';
import { AddressFormBlockComponent, AddressFormBlockData } from '../address';
import { NameFormBlockData } from '../name/name-form-block-data';
import { OrganisationFormBlockComponent } from '../organisation';
import { OrganisationFormBlockData } from '../organisation/organisation-form-block-data';
import { EmailFormBlockComponent } from '../email';
import { PhoneNumbersFormBlockComponent, PhoneNumbersFormBlockData } from '../phone-numbers';

@Component({
  selector: 'app-deviating-address-form-block',
  templateUrl: 'deviating-address-form-block.component.html',
  styleUrls: ['deviating-address-form-block.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush,
  exportAs: 'appDeviatingAddressFormBlock',
  standalone: false,
})
export class DeviatingAddressFormBlockComponent
  extends FormBlockGroup<DeviatingAddressFormBlockData>
  implements AfterViewInit
{
  @Input()
  organisation = false;

  @Input()
  email = false;

  @Input()
  phoneNumbers = false;

  @ViewChild(AddressFormBlockComponent, { static: false })
  private readonly _addressFormBlock: AddressFormBlockComponent;

  @ViewChild(EmailFormBlockComponent, { static: false })
  private readonly _emailFormBlock: AddressFormBlockComponent;

  @ViewChild(PhoneNumbersFormBlockComponent, { static: false })
  private readonly _phoneNumbersFormBlock: AddressFormBlockComponent;

  get tabIndexEnd() {
    return this.tabIndexStart + 10;
  }

  @Input() defaults: Partial<DeviatingAddressFormBlockData>;

  @Input()
  nameRequiredMarks: Array<keyof NameFormBlockData>;

  @Input()
  nameValidatorFns: Record<keyof NameFormBlockData, ValidatorFn[]>;

  @Input()
  addressRequiredMarks: Array<keyof AddressFormBlockData>;

  @Input()
  addressValidatorFns: Record<keyof AddressFormBlockData, ValidatorFn[]>;

  @Input()
  organisationRequiredMarks: Array<keyof OrganisationFormBlockData>;

  @Input()
  organisationValidatorFns: Record<keyof OrganisationFormBlockData, ValidatorFn[]>;

  @Input()
  emailRequiredMark = false;

  @Input()
  emailValidationFns: ValidatorFn[] = [];

  @Input()
  phoneNumbersRequiredMarks: Array<keyof PhoneNumbersFormBlockData>;

  @Input()
  phoneNumbersValidatorFns: Record<keyof PhoneNumbersFormBlockData, ValidatorFn[]>;

  get deviatingAddress() {
    return this.control.get('deviatingAddress') as UntypedFormControl;
  }

  constructor(
    private readonly _fb: UntypedFormBuilder,
    @Self() private _elementRef: ElementRef,
    private _cdr: ChangeDetectorRef,
  ) {
    super();
  }

  ngAfterViewInit(): void {}

  initializeControl(data?: DeviatingAddressFormBlockData): void {
    this.control = this._fb.group({
      deviatingAddress: this._fb.control(data?.deviatingAddress ?? false, this.getValidatorFn('deviatingAddress')),
    });
  }

  _patchValue(update: { previous: DeviatingAddressFormBlockData; current: DeviatingAddressFormBlockData }): void {
    this.control.patchValue({
      deviatingAddress: update.current?.deviatingAddress ?? false,
    });
  }

  addOrganisationGroup(cmp: FormBlock<OrganisationFormBlockData, UntypedFormGroup>) {
    if (!this.control.contains('organisation')) {
      this.control.addControl('organisation', cmp.control);
    }
    setTimeout(() => this._cdr.markForCheck(), 0);
  }

  removeOrganisationGroup() {
    if (this.control.contains('organisation')) {
      this.control.removeControl('organisation');
    }
    setTimeout(() => this._cdr.markForCheck(), 0);
  }

  addNameGroup(cmp: FormBlock<NameFormBlockData, UntypedFormGroup>) {
    if (!this.control.contains('name')) {
      this.control.addControl('name', cmp.control);
    }
    setTimeout(() => this._cdr.markForCheck(), 0);
  }

  removeNameGroup() {
    if (this.control.contains('name')) {
      this.control.removeControl('name');
    }
    setTimeout(() => this._cdr.markForCheck(), 0);
  }

  addAddressGroup(cmp: FormBlock<AddressFormBlockData, UntypedFormGroup>) {
    if (!this.control.contains('address')) {
      this.control.addControl('address', cmp.control);
    }
    setTimeout(() => this._cdr.markForCheck(), 0);
  }

  removeAddressGroup() {
    if (this.control.contains('address')) {
      this.control.removeControl('address');
    }
    setTimeout(() => this._cdr.markForCheck(), 0);
  }

  addEmailGroup(cmp: FormBlock<string, UntypedFormControl>) {
    if (!this.control.contains('email')) {
      this.control.addControl('email', cmp.control);
    }
    setTimeout(() => this._cdr.markForCheck(), 0);
  }

  removeEmailGroup() {
    if (this.control.contains('email')) {
      this.control.removeControl('email');
    }
    setTimeout(() => this._cdr.markForCheck(), 0);
  }

  addPhoneNumbersGroup(cmp: FormBlock<PhoneNumbersFormBlockData, UntypedFormGroup>) {
    if (!this.control.contains('phoneNumbers')) {
      this.control.addControl('phoneNumbers', cmp.control);
    }
    setTimeout(() => this._cdr.markForCheck(), 0);
  }

  removePhoneNumbersGroup() {
    if (this.control.contains('phoneNumbers')) {
      this.control.removeControl('phoneNumbers');
    }
    setTimeout(() => this._cdr.markForCheck(), 0);
  }

  setAddressValidationError(invalidProperties: Record<keyof AddressFormBlockData, string>) {
    this._addressFormBlock?.setAddressValidationError(invalidProperties);
  }

  updateValidators(): void {
    throw new Error('Method not implemented.');
  }
}
