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

import { IUnitConverter, NewUnitConverter } from '../unit-converter.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 IUnitConverter for edit and NewUnitConverterFormGroupInput for create.
 */
type UnitConverterFormGroupInput = IUnitConverter | PartialWithRequiredKeyOf<NewUnitConverter>;

type UnitConverterFormDefaults = Pick<NewUnitConverter, 'id'>;

type UnitConverterFormGroupContent = {
  id: FormControl<IUnitConverter['id'] | NewUnitConverter['id']>;
  name: FormControl<IUnitConverter['name']>;
  description: FormControl<IUnitConverter['description']>;
  convertionFormula: FormControl<IUnitConverter['convertionFormula']>;
  version: FormControl<IUnitConverter['version']>;
  fromUnit: FormControl<IUnitConverter['fromUnit']>;
  toUnit: FormControl<IUnitConverter['toUnit']>;
};

export type UnitConverterFormGroup = FormGroup<UnitConverterFormGroupContent>;

@Injectable({ providedIn: 'root' })
export class UnitConverterFormService {
  createUnitConverterFormGroup(unitConverter: UnitConverterFormGroupInput = { id: null }): UnitConverterFormGroup {
    const unitConverterRawValue = {
      ...this.getFormDefaults(),
      ...unitConverter,
    };
    return new FormGroup<UnitConverterFormGroupContent>({
      id: new FormControl(
        { value: unitConverterRawValue.id, disabled: true },
        {
          nonNullable: true,
          validators: [Validators.required],
        },
      ),
      name: new FormControl(unitConverterRawValue.name, {
        validators: [Validators.required],
      }),
      description: new FormControl(unitConverterRawValue.description),
      convertionFormula: new FormControl(unitConverterRawValue.convertionFormula, {
        validators: [Validators.required],
      }),
      version: new FormControl(unitConverterRawValue.version),
      fromUnit: new FormControl(unitConverterRawValue.fromUnit),
      toUnit: new FormControl(unitConverterRawValue.toUnit),
    });
  }

  getUnitConverter(form: UnitConverterFormGroup): IUnitConverter | NewUnitConverter {
    return form.getRawValue() as IUnitConverter | NewUnitConverter;
  }

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

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