import { InjectQueue } from '@nestjs/bullmq';
import { Injectable } from '@nestjs/common';
import { Queue } from 'bullmq';
import { Interval } from 'date-fns';
import { catchError, from, map, switchMap, tap, throwError } from 'rxjs';
import { TourService } from 'src/modules/feat-business-objects/entities/tour/tour.service';
import { TOURS_QUEUE } from 'src/modules/feat-business-objects/entities/tour/tour.tokens';
import { DispoLiveApiExtractorsService } from '../../feat-extractors/dispo-live-api-extractors.service';
import {
  parseCETDateTime,
  pick,
  transformProperties,
} from '../../feat-transformers/transformer.functions';

@Injectable()
export class TourUpdateChecker {
  constructor(
    private readonly tourService: TourService,
    private readonly dispoLiveApiService: DispoLiveApiExtractorsService,
    @InjectQueue(TOURS_QUEUE) private readonly toursQueue: Queue,
  ) {}

  async fetchTourUpdates(interval: Interval) {
    return await this.dispoLiveApiService.toursFindByRange(interval).pipe(
      switchMap((summaries) =>
        from(
          this.tourService.findUpdatedAtBetween(
            summaries.data.at(0)._id,
            summaries.data.at(-1)._id,
          ),
        ).pipe(
          map((savedTours) => {
            const deleted = [];
            const updated = [];
            const created = [];

            for (const summary of summaries.data) {
              const savedTour = savedTours.find(({ id }) => summary._id === id);
              if (!savedTour) created.push({ id: summary._id });
              const lastUpdateDate = summary?.lastUpdate
                ? transformProperties(parseCETDateTime('yyyy-MM-dd HH:mm:ss'))(
                    pick(['lastUpdate'])(
                      summary as Record<'lastUpdate', string>,
                    ),
                  )
                : undefined;

              if (
                lastUpdateDate?.lastUpdate.toISOString() !==
                savedTour?.updatedAt?.toISOString()
              ) {
                updated.push({ id: summary._id });
              }
            }

            for (const savedTour of savedTours) {
              const summary = summaries.data.find(
                ({ _id }) => savedTour.id === _id,
              );
              if (!summary) deleted.push({ id: savedTour.id });
            }

            return {
              created,
              updated,
              deleted,
            };
          }),
          switchMap(({ created, updated, deleted }) =>
            from(
              Promise.all([
                ...created.map(
                  async (summary) =>
                    await this.toursQueue.add(`Create`, summary),
                ),
                ...updated.map(
                  async (summary) =>
                    await this.toursQueue.add(`Update`, summary),
                ),
                this.tourService.deleteTours(deleted.map(({ id }) => id)),
              ]),
            ),
          ),
        ),
      ),
      catchError((err) => {
        console.log(err);
        return throwError(() => new Error('Something went wrong'));
      }),
    );
  }
}
