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

import { IEmissionFactor, NewEmissionFactor } from '../emission-factor.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 IEmissionFactor for edit and NewEmissionFactorFormGroupInput for create.
 */
type EmissionFactorFormGroupInput = IEmissionFactor | PartialWithRequiredKeyOf<NewEmissionFactor>;

type EmissionFactorFormDefaults = Pick<NewEmissionFactor, 'id'>;

type EmissionFactorFormGroupContent = {
  id: FormControl<IEmissionFactor['id'] | NewEmissionFactor['id']>;
  year: FormControl<IEmissionFactor['year']>;
  code: FormControl<IEmissionFactor['code']>;
  name: FormControl<IEmissionFactor['name']>;
  unit: FormControl<IEmissionFactor['unit']>;
  value: FormControl<IEmissionFactor['value']>;
  source: FormControl<IEmissionFactor['source']>;
  comments: FormControl<IEmissionFactor['comments']>;
  variableScope: FormControl<IEmissionFactor['variableScope']>;
  variableCategory: FormControl<IEmissionFactor['variableCategory']>;
  version: FormControl<IEmissionFactor['version']>;
};

export type EmissionFactorFormGroup = FormGroup<EmissionFactorFormGroupContent>;

@Injectable({ providedIn: 'root' })
export class EmissionFactorFormService {
  createEmissionFactorFormGroup(emissionFactor: EmissionFactorFormGroupInput = { id: null }): EmissionFactorFormGroup {
    const emissionFactorRawValue = {
      ...this.getFormDefaults(),
      ...emissionFactor,
    };
    return new FormGroup<EmissionFactorFormGroupContent>({
      id: new FormControl(
        { value: emissionFactorRawValue.id, disabled: true },
        {
          nonNullable: true,
          validators: [Validators.required],
        },
      ),
      year: new FormControl(emissionFactorRawValue.year, {
        validators: [Validators.required, Validators.pattern('^[0-9]*$')],
      }),
      code: new FormControl(emissionFactorRawValue.code, {
        validators: [Validators.required, Validators.pattern('^[0-9]*$')],
      }),
      name: new FormControl(emissionFactorRawValue.name, {
        validators: [Validators.required],
      }),
      unit: new FormControl(emissionFactorRawValue.unit, {
        validators: [Validators.required],
      }),
      value: new FormControl(emissionFactorRawValue.value, {
        validators: [Validators.required],
      }),
      source: new FormControl(emissionFactorRawValue.source),
      comments: new FormControl(emissionFactorRawValue.comments),
      variableScope: new FormControl(emissionFactorRawValue.variableScope),
      variableCategory: new FormControl(emissionFactorRawValue.variableCategory),
      version: new FormControl(emissionFactorRawValue.version),
    });
  }

  getEmissionFactor(form: EmissionFactorFormGroup): IEmissionFactor | NewEmissionFactor {
    return form.getRawValue() as IEmissionFactor | NewEmissionFactor;
  }

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

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