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

import { IOrganizationType, NewOrganizationType } from '../organization-type.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 IOrganizationType for edit and NewOrganizationTypeFormGroupInput for create.
 */
type OrganizationTypeFormGroupInput = IOrganizationType | PartialWithRequiredKeyOf<NewOrganizationType>;

type OrganizationTypeFormDefaults = Pick<NewOrganizationType, 'id' | 'metadataProperties'>;

type OrganizationTypeFormGroupContent = {
  id: FormControl<IOrganizationType['id'] | NewOrganizationType['id']>;
  code: FormControl<IOrganizationType['code']>;
  name: FormControl<IOrganizationType['name']>;
  description: FormControl<IOrganizationType['description']>;
  nature: FormControl<IOrganizationType['nature']>;
  icon: FormControl<IOrganizationType['icon']>;
  iconContentType: FormControl<IOrganizationType['iconContentType']>;
  version: FormControl<IOrganizationType['version']>;
  metadataProperties: FormControl<IOrganizationType['metadataProperties']>;
};

export type OrganizationTypeFormGroup = FormGroup<OrganizationTypeFormGroupContent>;

@Injectable({ providedIn: 'root' })
export class OrganizationTypeFormService {
  createOrganizationTypeFormGroup(organizationType: OrganizationTypeFormGroupInput = { id: null }): OrganizationTypeFormGroup {
    const organizationTypeRawValue = {
      ...this.getFormDefaults(),
      ...organizationType,
    };
    return new FormGroup<OrganizationTypeFormGroupContent>({
      id: new FormControl(
        { value: organizationTypeRawValue.id, disabled: true },
        {
          nonNullable: true,
          validators: [Validators.required],
        },
      ),
      code: new FormControl(organizationTypeRawValue.code, {
        validators: [Validators.required, Validators.minLength(1)],
      }),
      name: new FormControl(organizationTypeRawValue.name, {
        validators: [Validators.required, Validators.minLength(3)],
      }),
      description: new FormControl(organizationTypeRawValue.description, {
        validators: [Validators.required, Validators.minLength(3)],
      }),
      nature: new FormControl(organizationTypeRawValue.nature, {
        validators: [Validators.required],
      }),
      icon: new FormControl(organizationTypeRawValue.icon),
      iconContentType: new FormControl(organizationTypeRawValue.iconContentType),
      version: new FormControl(organizationTypeRawValue.version),
      metadataProperties: new FormControl(organizationTypeRawValue.metadataProperties ?? []),
    });
  }

  getOrganizationType(form: OrganizationTypeFormGroup): IOrganizationType | NewOrganizationType {
    return form.getRawValue() as IOrganizationType | NewOrganizationType;
  }

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

  private getFormDefaults(): OrganizationTypeFormDefaults {
    return {
      id: null,
      metadataProperties: [],
    };
  }
}
