import { RadiobuttonGroupDirection } from '@af/digi-ng/_form/form-radiobutton-group';
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { FormArray, FormControl, FormGroup } from '@angular/forms';
import { ActivatedRoute } from '@angular/router';
import { Activity } from '@msfa-models/activity.model';
import { DeltagareAvrop } from '@msfa-models/avrop.model';
import { CustomError } from '@msfa-models/error/custom-error';
import {
  GemensamPlanering,
  mapGemensamPlaneringToGemensamPlaneringPostRequest,
} from '@msfa-models/gemensam-planering.model';
import { Radiobutton } from '@ui/radiobutton-group/radiobutton.model';
import { addDays } from 'date-fns';
import { BehaviorSubject, Observable } from 'rxjs';
import { map, shareReplay, switchMap, take } from 'rxjs/operators';
import { GemensamPlaneringFormService } from './gemensam-planering-form.service';
import { GemensamPlaneringFormValidator } from './gemensam-planering-form.validator';

@Component({
  selector: 'msfa-gemensam-planering-form',
  templateUrl: './gemensam-planering-form.component.html',
  styleUrls: ['./gemensam-planering-form.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class GemensamPlaneringFormComponent {
  obligatoryActivityIds = [165, 188];
  shouldValidate$ = new BehaviorSubject<boolean>(false);
  RadiobuttonGroupDirection = RadiobuttonGroupDirection;
  confirmDialogOpen$ = new BehaviorSubject<boolean>(false);
  today = new Date();
  error$ = new BehaviorSubject<CustomError>(null);
  lastSubmittedGP$ = new BehaviorSubject<Date>(null);
  submitLoading$ = new BehaviorSubject<boolean>(false);

  activities$: Observable<Activity[]> = this.gemensamPlaneringFormService.activities$;
  currentGenomforandeReferens$: Observable<number> = this.activatedRoute.params.pipe(
    map(params => +params.genomforandeReferens)
  );
  avrop$: Observable<DeltagareAvrop> = this.currentGenomforandeReferens$.pipe(
    switchMap(genomforandeReferens => this.gemensamPlaneringFormService.fetchAvropInformation$(genomforandeReferens)),
    shareReplay(1)
  );

  gpFormGroup = new FormGroup(
    {
      distance: new FormControl(false),
      activityIds: new FormArray(this.obligatoryActivityIds.map(id => new FormControl(id))),
    },
    [GemensamPlaneringFormValidator.isGemensamPlaneringValid(this.obligatoryActivityIds)]
  );

  distanceRadiobuttons: Radiobutton[] = [
    { label: 'Ja', value: true },
    { label: 'Nej', value: false },
  ];

  get activityIdsFormArray(): FormArray {
    return this.gpFormGroup.get('activityIds') as FormArray;
  }

  get selectedActivityIds(): number[] {
    return this.activityIdsFormArray.value as number[];
  }

  get selectedActivityIdsExcludingObligatory(): number[] {
    return this.selectedActivityIds.filter(id => this.obligatoryActivityIds.indexOf(id) === -1);
  }

  isActivityChecked(id: number): boolean {
    return this.selectedActivityIds.includes(id);
  }

  isActivityObligatory(id: number): boolean {
    return this.obligatoryActivityIds.includes(id);
  }

  showActivityAsInvalid(id: number): boolean {
    if (this.shouldValidate$.getValue()) {
      if (this.isActivityObligatory(id) && !this.isActivityChecked(id)) {
        return true;
      }
      if (!this.isActivityObligatory(id) && !this.selectedActivityIdsExcludingObligatory.length) {
        return true;
      }
    }

    return false;
  }

  formControlIsInvalid(formControlName: string): boolean {
    return this.gpFormGroup.errors && this.gpFormGroup.errors[formControlName] && this.shouldValidate$.getValue();
  }

  constructor(
    private gemensamPlaneringFormService: GemensamPlaneringFormService,
    private activatedRoute: ActivatedRoute
  ) {}

  updateActivityIds(activityId: string, checked: boolean): void {
    if (checked) {
      this.activityIdsFormArray.push(new FormControl(+activityId));
    } else {
      const index: number = this.selectedActivityIds.findIndex(id => id === +activityId);

      if (index > -1) {
        this.activityIdsFormArray.removeAt(index);
      }
    }
  }

  openConfirmDialog(): void {
    this.shouldValidate$.next(true);

    if (this.gpFormGroup.invalid) {
      return;
    }
    this.confirmDialogOpen$.next(true);
  }

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

  submitAndCloseConfirmDialog(genomforandeReferens: number): void {
    this.submitLoading$.next(true);

    const { distance, activityIds } = this.gpFormGroup.value as GemensamPlanering;

    const postRequest = {
      distance,
      activityIds,
      genomforandeReferens,
    };

    this.gemensamPlaneringFormService
      .postGemensamPlanering$(mapGemensamPlaneringToGemensamPlaneringPostRequest(postRequest))
      .pipe(take(1))
      .subscribe({
        next: () => {
          this.lastSubmittedGP$.next(new Date());
          this.submitLoading$.next(false);
          this.confirmDialogOpen$.next(false);
        },
        error: (customError: CustomError) => {
          this.error$.next({ ...customError, message: customError.error.message });
          this.submitLoading$.next(false);
          throw { ...customError, avoidToast: true };
        },
      });
  }

  private _isAfterStartDate(startDate: Date): boolean {
    return new Date() > startDate;
  }
  private _isBeforeLastPossibleReportDay(endDate: Date): boolean {
    // Reporting is allowed at latest 5 days past avrop end date.
    // Because it's workdays and not calendar days we temporarily set this to much more. This date should be fetched from API in the future
    const lastPossibleReportDay = addDays(endDate, 15);
    return lastPossibleReportDay > new Date();
  }

  isAllowedToReport(avrop: DeltagareAvrop): boolean {
    return this._isAfterStartDate(avrop.startDate) && this._isBeforeLastPossibleReportDay(avrop.endDate);
  }

  notAllowedToReportWarning(avrop: DeltagareAvrop): string {
    if (!this._isBeforeLastPossibleReportDay(avrop.endDate)) {
      return 'Det går inte att göra Gemensam planering eftersom tjänsten har avslutats.';
    }
    if (!this._isAfterStartDate(avrop.startDate)) {
      return 'Det går inte att göra Gemensam planering eftersom tjänsten inte har startat ännu.';
    }
  }
}
