import { Injectable } from '@angular/core';
import { FormGroup, FormControl, Validators } from '@angular/forms';

import { IMetadataValue, NewMetadataValue } from '../metadata-value.model';

/**
 * A partial Type with required key is used as form input.
 */
type PartialWithRequiredKeyOf<T extends { id: unknown }> = Partial<Omit<T, 'id'>> & { id: T['id'] };

/**
 * Type for createFormGroup and resetForm argument.
 * It accepts IMetadataValue for edit and NewMetadataValueFormGroupInput for create.
 */
type MetadataValueFormGroupInput = IMetadataValue | PartialWithRequiredKeyOf<NewMetadataValue>;

type MetadataValueFormDefaults = Pick<NewMetadataValue, 'id'>;

type MetadataValueFormGroupContent = {
  id: FormControl<IMetadataValue['id'] | NewMetadataValue['id']>;
  metadataPropertyCode: FormControl<IMetadataValue['metadataPropertyCode']>;
  targetDomainKey: FormControl<IMetadataValue['targetDomainKey']>;
  targetDomainId: FormControl<IMetadataValue['targetDomainId']>;
  value: FormControl<IMetadataValue['value']>;
  version: FormControl<IMetadataValue['version']>;
};

export type MetadataValueFormGroup = FormGroup<MetadataValueFormGroupContent>;

@Injectable({ providedIn: 'root' })
export class MetadataValueFormService {
  createMetadataValueFormGroup(metadataValue: MetadataValueFormGroupInput = { id: null }): MetadataValueFormGroup {
    const metadataValueRawValue = {
      ...this.getFormDefaults(),
      ...metadataValue,
    };
    return new FormGroup<MetadataValueFormGroupContent>({
      id: new FormControl(
        { value: metadataValueRawValue.id, disabled: true },
        {
          nonNullable: true,
          validators: [Validators.required],
        },
      ),
      metadataPropertyCode: new FormControl(metadataValueRawValue.metadataPropertyCode, {
        validators: [Validators.required],
      }),
      targetDomainKey: new FormControl(metadataValueRawValue.targetDomainKey, {
        validators: [Validators.required],
      }),
      targetDomainId: new FormControl(metadataValueRawValue.targetDomainId, {
        validators: [Validators.required],
      }),
      value: new FormControl(metadataValueRawValue.value),
      version: new FormControl(metadataValueRawValue.version),
    });
  }

  getMetadataValue(form: MetadataValueFormGroup): IMetadataValue | NewMetadataValue {
    return form.getRawValue() as IMetadataValue | NewMetadataValue;
  }

  resetForm(form: MetadataValueFormGroup, metadataValue: MetadataValueFormGroupInput): void {
    const metadataValueRawValue = { ...this.getFormDefaults(), ...metadataValue };
    form.reset(
      {
        ...metadataValueRawValue,
        id: { value: metadataValueRawValue.id, disabled: true },
      } as any /* cast to workaround https://github.com/angular/angular/issues/46458 */,
    );
  }

  private getFormDefaults(): MetadataValueFormDefaults {
    return {
      id: null,
    };
  }
}
