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

import { IVariableClass, NewVariableClass } from '../variable-class.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 IVariableClass for edit and NewVariableClassFormGroupInput for create.
 */
type VariableClassFormGroupInput = IVariableClass | PartialWithRequiredKeyOf<NewVariableClass>;

type VariableClassFormDefaults = Pick<NewVariableClass, 'id'>;

type VariableClassFormGroupContent = {
  id: FormControl<IVariableClass['id'] | NewVariableClass['id']>;
  code: FormControl<IVariableClass['code']>;
  name: FormControl<IVariableClass['name']>;
  version: FormControl<IVariableClass['version']>;
  variableClassType: FormControl<IVariableClass['variableClassType']>;
};

export type VariableClassFormGroup = FormGroup<VariableClassFormGroupContent>;

@Injectable({ providedIn: 'root' })
export class VariableClassFormService {
  createVariableClassFormGroup(variableClass: VariableClassFormGroupInput = { id: null }): VariableClassFormGroup {
    const variableClassRawValue = {
      ...this.getFormDefaults(),
      ...variableClass,
    };
    return new FormGroup<VariableClassFormGroupContent>({
      id: new FormControl(
        { value: variableClassRawValue.id, disabled: true },
        {
          nonNullable: true,
          validators: [Validators.required],
        },
      ),
      code: new FormControl(variableClassRawValue.code, {
        validators: [Validators.required],
      }),
      name: new FormControl(variableClassRawValue.name, {
        validators: [Validators.required],
      }),
      version: new FormControl(variableClassRawValue.version),
      variableClassType: new FormControl(variableClassRawValue.variableClassType),
    });
  }

  getVariableClass(form: VariableClassFormGroup): IVariableClass | NewVariableClass {
    return form.getRawValue() as IVariableClass | NewVariableClass;
  }

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

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