import { Injectable } from '@nestjs/common';
import {
  AttendanceRegistrationStaging,
  EmployeeDispoLiveSource,
  EmployeeDispoLiveStaging,
  EmployeeDyflexisSource,
  EmployeeDyflexisStaging,
  PatientStaging,
  PlannedTimeStaging,
  Prisma,
  TourStaging,
  WorkTimeStaging,
} from '@prisma/client';
import { from, map, switchMap } from 'rxjs';

import { ExtractorsService } from '../feat-extractors/extractors.service';
import { ToursCalculationAdapater } from './adapter/tours-calculation.adapter';
import { StagingRepository } from './staging.repository';
import { AttendanceRegistrationTransformer } from './transformers/attendance-registration.transformer';
import { DispoliveEmployeeTransformer } from './transformers/employee-dispolive.transformer';
import { DyflexisEmployeeTransformer } from './transformers/employee-dyflexis.transformer';
import { PatientTransformer } from './transformers/patient.transformer';
import { PlannedTimeTransformer } from './transformers/planned-time.transformer';
import { TourTransformer } from './transformers/tour.transformer';
import { WorkTimeTransformer } from './transformers/work-time.transformer';

@Injectable()
export class TransformersService {
  constructor(
    private readonly extractorsService: ExtractorsService,
    private readonly repository: StagingRepository,
    private readonly tourCalculationAdapter: ToursCalculationAdapater,
  ) {}

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

  transformPlannedTimes(jobId: string) {
    return from(this.extractorsService.findPlannedTimesByJobId(jobId)).pipe(
      map((plannedTimes) =>
        plannedTimes.map((plannedTime) =>
          PlannedTimeTransformer.transform(plannedTime),
        ),
      ),
      switchMap((plannedTimes) =>
        this.repository.createPlannedTimes(plannedTimes),
      ),
    );
  }

  transformWorkTimes(jobId: string) {
    return from(this.extractorsService.findWorkTimesByJobId(jobId)).pipe(
      map((workTimes) =>
        workTimes.map((workTime) => WorkTimeTransformer.transform(workTime)),
      ),
      switchMap((workTimes) => this.repository.createWorkTimes(workTimes)),
    );
  }

  transformAttendanceRegistrations(jobId: string) {
    return from(
      this.extractorsService.findAttendanceRegistrationsByJobId(jobId),
    ).pipe(
      map((attendanceRegistrations) =>
        attendanceRegistrations.map((attendanceRegistration) =>
          AttendanceRegistrationTransformer.transform(attendanceRegistration),
        ),
      ),
      switchMap((attendanceRegistrations) =>
        this.repository.createAttendanceRegistrations(attendanceRegistrations),
      ),
    );
  }

  transformTours(jobId: string) {
    return from(this.extractorsService.findToursByJobId(jobId)).pipe(
      // TODO: Add validation filter
      map((tours) =>
        tours
          .filter(({ einsatzNummer }) => !!einsatzNummer)
          .map((tour) => TourTransformer.transform(tour)),
      ),
      switchMap((tours) =>
        from(
          this.tourCalculationAdapter.addRevenueAndConsumptionCostsToTours(
            tours,
          ),
        ),
      ),
      switchMap((tours) => this.repository.createTours(tours)),
    );
  }

  transformDyflexisEmployees(jobId: string) {
    return from(
      this.extractorsService.findEmployeesDyflexisByJobId(jobId),
    ).pipe(
      map((employees) =>
        employees.map((dyflexisEmployee) =>
          DyflexisEmployeeTransformer.transform(
            dyflexisEmployee as EmployeeDyflexisSource,
          ),
        ),
      ),
      switchMap((employees) =>
        this.repository.createDyflexisEmployees(employees),
      ),
    );
  }

  transformDispoliveEmployees(jobId: string) {
    return from(
      this.extractorsService.findEmployeesDispoLiveByJobId(jobId),
    ).pipe(
      map((employees) =>
        employees.map((dispoLiveEmployee) =>
          DispoliveEmployeeTransformer.transform(
            dispoLiveEmployee as EmployeeDispoLiveSource,
          ),
        ),
      ),
      switchMap((employees) =>
        this.repository.createDispoliveEmployees(employees),
      ),
    );
  }

  transformPatients(jobId: string) {
    return from(this.extractorsService.findPatientsByJobId(jobId)).pipe(
      map((patients) =>
        patients.map((patient) => PatientTransformer.transform(patient)),
      ),
      switchMap((patients) => this.repository.createPatients(patients)),
    );
  }

  findPatients(): Promise<PatientStaging[]> {
    return this.repository.findPatients();
  }

  findDyflexisEmployees(): Promise<EmployeeDyflexisStaging[]> {
    return this.repository.findDyflexisEmployees();
  }

  findDispoliveEmployees(): Promise<EmployeeDispoLiveStaging[]> {
    return this.repository.findDispoliveEmployees();
  }

  findTours(): Promise<TourStaging[]> {
    return this.repository.findTours();
  }

  findAttendanceRegistrations(): Promise<AttendanceRegistrationStaging[]> {
    return this.repository.findAttendanceRegistrations();
  }

  findPlannedTimes(): Promise<PlannedTimeStaging[]> {
    return this.repository.findPlannedTimes();
  }

  findWorkTimes(): Promise<WorkTimeStaging[]> {
    return this.repository.findWorkTimes();
  }
}
