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

import { IUnit, NewUnit } from '../unit.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 IUnit for edit and NewUnitFormGroupInput for create.
 */
type UnitFormGroupInput = IUnit | PartialWithRequiredKeyOf<NewUnit>;

type UnitFormDefaults = Pick<NewUnit, 'id'>;

type UnitFormGroupContent = {
  id: FormControl<IUnit['id'] | NewUnit['id']>;
  code: FormControl<IUnit['code']>;
  symbol: FormControl<IUnit['symbol']>;
  name: FormControl<IUnit['name']>;
  description: FormControl<IUnit['description']>;
  convertionRate: FormControl<IUnit['convertionRate']>;
  version: FormControl<IUnit['version']>;
  unitType: FormControl<IUnit['unitType']>;
};

export type UnitFormGroup = FormGroup<UnitFormGroupContent>;

@Injectable({ providedIn: 'root' })
export class UnitFormService {
  createUnitFormGroup(unit: UnitFormGroupInput = { id: null }): UnitFormGroup {
    const unitRawValue = {
      ...this.getFormDefaults(),
      ...unit,
    };
    return new FormGroup<UnitFormGroupContent>({
      id: new FormControl(
        { value: unitRawValue.id, disabled: true },
        {
          nonNullable: true,
          validators: [Validators.required],
        },
      ),
      code: new FormControl(unitRawValue.code, {
        validators: [Validators.required],
      }),
      symbol: new FormControl(unitRawValue.symbol, {
        validators: [Validators.required],
      }),
      name: new FormControl(unitRawValue.name, {
        validators: [Validators.required],
      }),
      description: new FormControl(unitRawValue.description),
      convertionRate: new FormControl(unitRawValue.convertionRate, {
        validators: [Validators.required],
      }),
      version: new FormControl(unitRawValue.version),
      unitType: new FormControl(unitRawValue.unitType),
    });
  }

  getUnit(form: UnitFormGroup): IUnit | NewUnit {
    return form.getRawValue() as IUnit | NewUnit;
  }

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

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