import { Anomaly, Prisma } from '@prisma/client';
import { Interval } from 'date-fns';

import { AnomalyDetectorService } from './anomaly-detector.service';

export type AnomalySkeleton = Pick<
  Prisma.AnomalyCreateInput,
  | 'associatedEntities'
  | 'createdAt'
  | 'workedOnBy'
  | 'sleepTimer'
  | 'sleepSince'
>;
export abstract class AnomalyDetector {
  private associatedEntities: Record<string, { id: string }[]> = {};

  constructor(protected readonly dataService: AnomalyDetectorService) {}
  /**
   * Unique identifier of the Anomaly Type which is implemented by the class
   * TODO: Make the type typesafe
   */
  abstract readonly type: string;
  /**
   * Generic method call to detect anomalies in the data
   */
  abstract detect(inInterval: Interval): Promise<Prisma.AnomalyCreateInput[]>;
  /**
   * Generic method call to validate if an anomaly has been solved
   */
  abstract validate(anomaly: Anomaly): Promise<Anomaly>;
  abstract createDescription(data: unknown): string;
  abstract createSolution(data: unknown): Prisma.SolutionTargetCreateInput[];

  protected addAssociatedEntity(type: string, id: string): void {
    this.associatedEntities = {
      ...this.associatedEntities,
      [type]: [
        ...(this.associatedEntities[type]?.length
          ? this.associatedEntities[type]
          : []),
        { id },
      ],
    };
  }

  protected flushAssociatedEntities(): void {
    this.associatedEntities = {};
  }

  protected getAnomalySkeleton(): AnomalySkeleton {
    const associatedEntities = this.associatedEntities;
    this.flushAssociatedEntities();

    return {
      associatedEntities,
      createdAt: new Date(),
      workedOnBy: '',
      sleepTimer: 60 * 60 * 1000,
      sleepSince: null,
    };
  }
}
