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

import { IContentPage, NewContentPage } from '../content-page.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 IContentPage for edit and NewContentPageFormGroupInput for create.
 */
type ContentPageFormGroupInput = IContentPage | PartialWithRequiredKeyOf<NewContentPage>;

type ContentPageFormDefaults = Pick<NewContentPage, 'id'>;

type ContentPageFormGroupContent = {
  id: FormControl<IContentPage['id'] | NewContentPage['id']>;
  title: FormControl<IContentPage['title']>;
  slug: FormControl<IContentPage['slug']>;
  content: FormControl<IContentPage['content']>;
  version: FormControl<IContentPage['version']>;
};

export type ContentPageFormGroup = FormGroup<ContentPageFormGroupContent>;

@Injectable({ providedIn: 'root' })
export class ContentPageFormService {
  createContentPageFormGroup(contentPage: ContentPageFormGroupInput = { id: null }): ContentPageFormGroup {
    const contentPageRawValue = {
      ...this.getFormDefaults(),
      ...contentPage,
    };
    return new FormGroup<ContentPageFormGroupContent>({
      id: new FormControl(
        { value: contentPageRawValue.id, disabled: true },
        {
          nonNullable: true,
          validators: [Validators.required],
        },
      ),
      title: new FormControl(contentPageRawValue.title, {
        validators: [Validators.required],
      }),
      slug: new FormControl(contentPageRawValue.slug, {
        validators: [Validators.required],
      }),
      content: new FormControl(contentPageRawValue.content, {
        validators: [Validators.required],
      }),
      version: new FormControl(contentPageRawValue.version),
    });
  }

  getContentPage(form: ContentPageFormGroup): IContentPage | NewContentPage {
    return form.getRawValue() as IContentPage | NewContentPage;
  }

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

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