import { Logger } from '@nestjs/common';
import { Anomaly, Prisma } from '@prisma/client';
import { Interval, format } from 'date-fns';
import { toZonedTime } from 'date-fns-tz';
import { AnomalyTypes } from 'src/modules/feat-business-objects/entities/anomaly/anomaly-types.enum';
import { AnomalyDetector } from './anomaly-detector.class';

export class DriverCodriverSameDetector extends AnomalyDetector {
  private readonly logger = new Logger(DriverCodriverSameDetector.name);
  readonly type = AnomalyTypes.DriverCodriverSame;

  async detect(inInterval: Interval): Promise<Prisma.AnomalyCreateInput[]> {
    const toursInRange = await this.dataService.findToursInInterval(
      inInterval,
      ['KTW'],
    );

    const anomalies = await Promise.all(
      toursInRange.map(
        ({
          id: tourId,
          operationId,
          carName,
          startDate,
          driverId,
          codriverId,
        }) => {
          if (driverId === codriverId && driverId !== null) {
            this.addAssociatedEntity('tour', tourId);
            this.addAssociatedEntity('employee', driverId);
            
            return this.createAnomaly(
              `${operationId}-${this.type}`,
              operationId,
              carName,
              startDate,
            );
          }
        },
      ),
    );
    return anomalies.filter((anomaly) => !!anomaly);
  }

  async validate(anomaly: Anomaly): Promise<Anomaly> {
    const [operationId] = anomaly.id.split('-');
    const tour = await this.dataService.findTourByOperationId(operationId);
    if (tour?.driverId !== tour?.codriverId) {
      return {
        ...anomaly,
        resolvedAt: new Date(),
      };
    }
    return { ...anomaly };
  }

  createDescription({ carName }: { carName: string }): string {
    return `${carName}: Fahrer und Beifahrer identisch`;
  }

  createSolution({
    carName,
  }: {
    carName: string;
  }): Prisma.SolutionTargetCreateInput[] {
    return [
      {
        name: `Fahrzeug ${carName}`,
        steps: {
          create: [
            {
              description: `Stellen Sie sicher, dass im Fahrzeug zwei Personen sitzen.`,
            },
          ],
        },
      },
    ];
  }

  private createAnomaly(
    anomalyId: string,
    operationId: string,
    carName: string,
    startDate: Date,
  ): Prisma.AnomalyCreateInput {
    return {
      ...this.getAnomalySkeleton(),
      id: anomalyId,
      type: this.type,
      groupKey: `${format(
        new Date(startDate),
        'yyyy-MM-dd-HH-mm',
      )}-${operationId}`,
      groupDescription: `${operationId} - ${format(
        toZonedTime(new Date(startDate), 'Europe/Berlin'),
        'HH:mm dd.MM.yy',
      )}`,
      solution: { create: this.createSolution({ carName }) },
      description: this.createDescription({ carName }),
    };
  }
}
