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

import { IOrganization, NewOrganization } from '../organization.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 IOrganization for edit and NewOrganizationFormGroupInput for create.
 */
type OrganizationFormGroupInput = IOrganization | PartialWithRequiredKeyOf<NewOrganization>;

type OrganizationFormDefaults = Pick<NewOrganization, 'id' | 'inputInventory' | 'outputInventory'>;

type OrganizationFormGroupContent = {
  id: FormControl<IOrganization['id'] | NewOrganization['id']>;
  code: FormControl<IOrganization['code']>;
  name: FormControl<IOrganization['name']>;
  image: FormControl<IOrganization['image']>;
  imageContentType: FormControl<IOrganization['imageContentType']>;
  inputInventory: FormControl<IOrganization['inputInventory']>;
  outputInventory: FormControl<IOrganization['outputInventory']>;
  version: FormControl<IOrganization['version']>;
  sort: FormControl<IOrganization['sort']>;
  user: FormControl<IOrganization['user']>;
  parent: FormControl<IOrganization['parent']>;
  organizationType: FormControl<IOrganization['organizationType']>;
};

export type OrganizationFormGroup = FormGroup<OrganizationFormGroupContent>;

@Injectable({ providedIn: 'root' })
export class OrganizationFormService {
  createOrganizationFormGroup(organization: OrganizationFormGroupInput = { id: null }): OrganizationFormGroup {
    const organizationRawValue = {
      ...this.getFormDefaults(),
      ...organization,
    };
    return new FormGroup<OrganizationFormGroupContent>({
      id: new FormControl(
        { value: organizationRawValue.id, disabled: true },
        {
          nonNullable: true,
          validators: [Validators.required],
        },
      ),
      code: new FormControl(organizationRawValue.code, {
        validators: [Validators.required, Validators.minLength(3)],
      }),
      name: new FormControl(organizationRawValue.name, {
        validators: [Validators.required, Validators.minLength(3)],
      }),
      image: new FormControl(organizationRawValue.image),
      imageContentType: new FormControl(organizationRawValue.imageContentType),
      inputInventory: new FormControl(organizationRawValue.inputInventory),
      outputInventory: new FormControl(organizationRawValue.outputInventory),
      version: new FormControl(organizationRawValue.version),
      sort: new FormControl(organizationRawValue.sort),
      user: new FormControl(organizationRawValue.user),
      parent: new FormControl(organizationRawValue.parent),
      organizationType: new FormControl(organizationRawValue.organizationType),
    });
  }

  getOrganization(form: OrganizationFormGroup): IOrganization | NewOrganization {
    return form.getRawValue() as IOrganization | NewOrganization;
  }

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

  private getFormDefaults(): OrganizationFormDefaults {
    return {
      id: null,
      inputInventory: false,
      outputInventory: false,
    };
  }
}
