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

import { IVariableScope, NewVariableScope } from '../variable-scope.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 IVariableScope for edit and NewVariableScopeFormGroupInput for create.
 */
type VariableScopeFormGroupInput = IVariableScope | PartialWithRequiredKeyOf<NewVariableScope>;

type VariableScopeFormDefaults = Pick<NewVariableScope, 'id'>;

type VariableScopeFormGroupContent = {
  id: FormControl<IVariableScope['id'] | NewVariableScope['id']>;
  code: FormControl<IVariableScope['code']>;
  name: FormControl<IVariableScope['name']>;
  description: FormControl<IVariableScope['description']>;
  version: FormControl<IVariableScope['version']>;
  hiddenForData: FormControl<IVariableScope['hiddenForData']>;
  hiddenForFactor: FormControl<IVariableScope['hiddenForFactor']>;
};

export type VariableScopeFormGroup = FormGroup<VariableScopeFormGroupContent>;

@Injectable({ providedIn: 'root' })
export class VariableScopeFormService {
  createVariableScopeFormGroup(variableScope: VariableScopeFormGroupInput = { id: null }): VariableScopeFormGroup {
    const variableScopeRawValue = {
      ...this.getFormDefaults(),
      ...variableScope,
    };
    return new FormGroup<VariableScopeFormGroupContent>({
      id: new FormControl(
        { value: variableScopeRawValue.id, disabled: true },
        {
          nonNullable: true,
          validators: [Validators.required],
        },
      ),
      code: new FormControl(variableScopeRawValue.code, {
        validators: [Validators.required, Validators.pattern('^[0-9]*$')],
      }),
      name: new FormControl(variableScopeRawValue.name, {
        validators: [Validators.required],
      }),
      description: new FormControl(variableScopeRawValue.description, {
        validators: [Validators.required],
      }),
      version: new FormControl(variableScopeRawValue.version),
      hiddenForData: new FormControl(variableScopeRawValue.hiddenForData),
      hiddenForFactor: new FormControl(variableScopeRawValue.hiddenForFactor),
    });
  }

  getVariableScope(form: VariableScopeFormGroup): IVariableScope | NewVariableScope {
    return form.getRawValue() as IVariableScope | NewVariableScope;
  }

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

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