import { Injectable, Logger } from '@nestjs/common';
import {
  AttendanceRegistrationSource,
  EmployeeDispoLiveSource,
  EmployeeDyflexisSource,
  PatientSource,
  PlannedTimeSource,
  Prisma,
  TourSource,
  WorkTimeSource,
} from '@prisma/client';
import { Interval } from 'date-fns';
import { Observable, catchError, combineLatest, map } from 'rxjs';
import { DispoLiveExtractorsService } from './dispo-live-extractors.service';
import { DyflexisExtractorsService } from './dyflexis-extractors.service';
import { SourceRepository } from './source.repository';

@Injectable()
export class ExtractorsService {
  private logger = new Logger(ExtractorsService.name);

  constructor(
    private readonly dispoLiveExtractors: DispoLiveExtractorsService,
    private readonly dyflexisExtractors: DyflexisExtractorsService,
    private readonly repository: SourceRepository,
  ) {}

  clearSource(): Promise<Prisma.BatchPayload[]> {
    return this.repository.clearSource();
  }

  extractTours(
    interval: Interval,
    jobId: string,
  ): Observable<Prisma.BatchPayload> {
    return this.dispoLiveExtractors.extractTours(interval, jobId).pipe(
      catchError((error) => {
        this.logger.error(error);
        throw error;
      }),
    );
  }

  extractEmployees(jobId: string): Observable<Prisma.BatchPayload> {
    return combineLatest([
      this.dispoLiveExtractors.extractEmployees(jobId),
      this.dyflexisExtractors.extractEmployees(jobId),
    ]).pipe(
      map(([{ count: countDispoLive }, { count: countDyflexis }]) => {
        return {
          count: countDispoLive + countDyflexis,
        };
      }),
      catchError((error) => {
        this.logger.error(error);
        throw error;
      }),
    );
  }

  extractPatients(jobId: string): Observable<Prisma.BatchPayload> {
    return this.dispoLiveExtractors.extractPatients(jobId).pipe(
      catchError((error) => {
        this.logger.error(error);
        throw error;
      }),
    );
  }

  extractPlannedTimes(
    interval: Interval,
    jobId: string,
  ): Observable<Prisma.BatchPayload> {
    return this.dyflexisExtractors.extractPlannedTimes(interval, jobId).pipe(
      catchError((error) => {
        this.logger.error(error);
        throw error;
      }),
    );
  }

  extractWorkTimes(
    interval: Interval,
    jobId: string,
  ): Observable<Prisma.BatchPayload> {
    return this.dyflexisExtractors.extractWorkTimes(interval, jobId).pipe(
      catchError((error) => {
        this.logger.error(error);
        throw error;
      }),
    );
  }

  extractAttendanceRegistrations(
    interval: Interval,
    jobId: string,
  ): Observable<Prisma.BatchPayload> {
    return this.dyflexisExtractors
      .extractAttendanceRegistrations(interval, jobId)
      .pipe(
        catchError((error) => {
          this.logger.error(error);
          throw error;
        }),
      );
  }

  findToursByJobId(jobId: string): Promise<TourSource[]> {
    return this.repository.findToursByJobId(jobId);
  }

  findPatientsByJobId(jobId: string): Promise<PatientSource[]> {
    return this.repository.findPatientsByJobId(jobId);
  }

  findPlannedTimesByJobId(jobId: string): Promise<PlannedTimeSource[]> {
    return this.repository.findPlannedTimesByJobId(jobId);
  }

  findWorkTimesByJobId(jobId: string): Promise<WorkTimeSource[]> {
    return this.repository.findWorkTimesByJobId(jobId);
  }

  findAttendanceRegistrationsByJobId(
    jobId: string,
  ): Promise<AttendanceRegistrationSource[]> {
    return this.repository.findAttendanceRegistrationsByJobId(jobId);
  }

  findEmployeesDispoLiveByJobId(
    jobId: string,
  ): Promise<EmployeeDispoLiveSource[]> {
    return this.repository.findEmployeesDispoLiveByJobId(jobId);
  }

  findEmployeesDyflexisByJobId(
    jobId: string,
  ): Promise<EmployeeDyflexisSource[]> {
    return this.repository.findEmployeesDyflexisByJobId(jobId);
  }
}
