import { SelectOption } from '@ui/select/select-option.model';
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { FormControl, FormGroup } from '@angular/forms';
import { ActivatedRoute } from '@angular/router';
import { InformativRapportCategory, InformativRapportCategoryKey } from '@msfa-enums/informativ-rapport-category.enum';
import {
  InformativRapportRequest,
  InformativRapportWithFileRequest,
} from '@msfa-models/api/informativ-rapport.request.model';
import { DeltagareAvrop } from '@msfa-models/avrop.model';
import { CustomError } from '@msfa-models/error/custom-error';
import { RequiredValidator } from '@msfa-utils/validators/required.validator';
import { BehaviorSubject, combineLatest, Observable } from 'rxjs';
import { map, shareReplay, switchMap, take } from 'rxjs/operators';
import { InformativRapportFormData } from './informativ-rapport-form.model';
import { InformativRapportFormService } from './informativ-rapport-form.service';
import { DomSanitizer } from '@angular/platform-browser';

@Component({
  selector: 'msfa-informativ-rapport-form',
  templateUrl: './informativ-rapport-form.component.html',
  styleUrls: ['./informativ-rapport-form.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class InformativRapportFormComponent {
  categoryDocumentSelected = false;
  shouldValidate$ = new BehaviorSubject<boolean>(false);
  confirmDialogOpen$ = new BehaviorSubject<boolean>(false);
  categoryInformationDialogOpen$ = new BehaviorSubject<boolean>(false);
  submitLoading$ = new BehaviorSubject<boolean>(false);
  lastSubmittedInformativRapport$ = new BehaviorSubject<Date>(null);
  submitError$ = new BehaviorSubject<CustomError>(null);
  genomforandeReferens$: Observable<number> = this.activatedRoute.params.pipe(
    map(params => +params.genomforandeReferens)
  );
  avrop$: Observable<DeltagareAvrop> = this.genomforandeReferens$.pipe(
    switchMap(genomforandeReferens => this.informativRapportFormService.fetchAvropInformation$(genomforandeReferens)),
    shareReplay(1)
  );

  informativRapportFormGroup = new FormGroup({
    category: new FormControl(null, [RequiredValidator('Ett ärende måste väljas')]),
    comment: new FormControl('', [RequiredValidator('Kompletterande information är obligatoriskt')]),
    file: new FormControl(null),
  });
  categorySelectItems: SelectOption[] = Object.entries(InformativRapportCategory).map(([value, name]) => ({
    name,
    value,
  }));

  formData$: Observable<InformativRapportFormData> = this.informativRapportFormGroup
    .valueChanges as Observable<InformativRapportFormData>;

  submitData$ = combineLatest([this.genomforandeReferens$, this.formData$]).pipe(
    map(([genomforandeReferens, formData]) => this._formDataToSubmitData(genomforandeReferens, formData)),
    shareReplay(1)
  );
  constructor(
    private informativRapportFormService: InformativRapportFormService,
    private activatedRoute: ActivatedRoute,
    private domSanitizer: DomSanitizer
  ) {}

  get categoryFormControl(): FormControl {
    return this.informativRapportFormGroup.get('category') as FormControl;
  }
  get commentFormControl(): FormControl {
    return this.informativRapportFormGroup.get('comment') as FormControl;
  }
  get fileFormControl(): FormControl {
    return this.informativRapportFormGroup.get('file') as FormControl;
  }

  private _formDataToSubmitData(
    genomforandeReferens: number,
    formData: InformativRapportFormData
  ): InformativRapportRequest | InformativRapportWithFileRequest {
    const { category, comment } = formData;

    const file: File = (this.fileFormControl?.value as File) ?? null;

    return this.categoryDocumentSelected
      ? { genomforandeReferens, category, comment, file }
      : { genomforandeReferens, category, comment };
  }

  getInformativRapportFileUrl(doc: File): string {
    const url = URL.createObjectURL(new Blob([doc]));
    return this.domSanitizer.bypassSecurityTrustUrl(url) as string;
  }

  private _markFormAsTouchedAndDirty(): void {
    this.informativRapportFormGroup.markAllAsTouched();
    this.commentFormControl.markAsDirty();
    this.categoryFormControl.markAsDirty();
    this.fileFormControl?.markAsDirty();
  }

  setUploadedFile(file: File): void {
    this.fileFormControl.setValue(file[0]);
  }

  removeUploadedFile(): void {
    this.fileFormControl.setValue(null);
  }

  getInformativRapportCategory(category: InformativRapportCategoryKey): InformativRapportCategory {
    return InformativRapportCategory[category] as InformativRapportCategory;
  }

  formControlIsInvalid(formControlName: string): boolean {
    return this.informativRapportFormGroup.get(formControlName).errors && this.shouldValidate$.getValue();
  }

  openCategoryInformationDialog(): void {
    this.categoryInformationDialogOpen$.next(true);
  }

  closeCategoryInformationDialog(): void {
    this.categoryInformationDialogOpen$.next(false);
  }

  categorySelectChange(category: string): void {
    this.categoryDocumentSelected = category === 'dokument';

    this.informativRapportFormGroup
      .get('file')
      .setValidators(this.categoryDocumentSelected ? [RequiredValidator('En fil måste väljas')] : null);

    if (!this.categoryDocumentSelected) {
      this.removeUploadedFile();
    }
  }

  openConfirmDialog(): void {
    this.shouldValidate$.next(true);
    this._markFormAsTouchedAndDirty();
    if (this.informativRapportFormGroup.invalid) {
      return;
    }

    this.confirmDialogOpen$.next(true);
  }

  cancelConfirmDialog(): void {
    this.confirmDialogOpen$.next(false);
    this.submitError$.next(null);
  }

  submitAndCloseConfirmDialog(): void {
    this.submitLoading$.next(true);
    this.submitData$.pipe(take(1)).subscribe(submitData =>
      this.informativRapportFormService.postInformativRapport$(submitData).subscribe({
        next: () => {
          this.submitLoading$.next(false);
          this.lastSubmittedInformativRapport$.next(new Date());
          this.confirmDialogOpen$.next(false);
        },
        error: (customError: CustomError) => {
          this.submitError$.next({ ...customError, message: customError.error.message });
          this.submitLoading$.next(false);
          throw { ...customError, avoidToast: true };
        },
      })
    );
  }
}
