import { Injectable } from '@nestjs/common';
import { PlannedTime, Tour } from '@prisma/client';
import { Interval } from 'date-fns';
import { generateIntervalForTimeRange } from 'src/utils';
import { PlannedTimeService } from '../entities/planned-time/planned-time.service';
import { TourService } from '../entities/tour/tour.service';
import { CarEntity } from './car.entity';

@Injectable()
export class CarEntityService {
  constructor(
    private readonly plannedTimeService: PlannedTimeService,
    private readonly tourService: TourService,
  ) {}

  async getCarsInInterval(
    interval: Interval,
    ordinanceType: string,
  ): Promise<CarEntity[]> {
    const carEntities = await this.generateCarEntitiesForInterval(
      interval,
      ordinanceType,
    );
    return carEntities;
  }

  async getCarsForOperationDay(
    day: Date,
    ordinanceType: string,
  ): Promise<CarEntity[]> {
    const operationDayInterval = generateIntervalForTimeRange(
      '05:00-04:59',
      'Europe/Berlin',
      day,
    );

    const carEntities = await this.generateCarEntitiesForInterval(
      operationDayInterval,
      ordinanceType,
    );
    return carEntities;
  }

  private async generateCarEntitiesForInterval(
    interval: Interval,
    ordinanceType: string,
  ): Promise<CarEntity[]> {
    const toursInFullRange = await this.tourService.findInInterval(interval);
    const plannedTimeByOrdinanceType =
      await this.plannedTimeService.findByOrdinanceTypesInInterval(
        ordinanceType,
        interval,
      );
    return this.generateCarEntities(
      toursInFullRange,
      plannedTimeByOrdinanceType,
      ordinanceType,
    );
  }

  private generateCarEntities(
    tours: Tour[],
    plannedTimes: PlannedTime[],
    ordinanceType: string,
  ): CarEntity[] {
    const departmentsAsCarNames = [
      ...new Set(plannedTimes.map(({ department }) => department)),
    ];

    const toursWithoutCarName = tours
      .filter((tour) => tour?.ordinanceType?.includes(ordinanceType))
      .filter(({ carName }) => !carName);

    return [
      ...departmentsAsCarNames.map((departmentAsCarName) => {
        const toursForCarName = tours.filter(({ carName }) =>
          this.isCarNameForDepartment(departmentAsCarName, carName),
        );
        const plannedTimesForCarName = plannedTimes.filter(
          ({ department }) => department === departmentAsCarName,
        );

        return new CarEntity(
          toursForCarName,
          plannedTimesForCarName,
          departmentAsCarName,
          ordinanceType,
        );
      }),
      ...(toursWithoutCarName.length
        ? [new CarEntity(toursWithoutCarName, [], undefined, ordinanceType)]
        : []),
    ];
  }

  private isCarNameForDepartment(department: string, carName: string): boolean {
    if (!department || !carName) return false;
    const [ordinanceType, carNumber] = department
      .replace('1/', '')
      .replace('E', '')
      .split('-')
      .map((part) => part.trim());
    return (
      (carName.indexOf(ordinanceType) > -1 &&
        carName.indexOf(carNumber) > -1) ||
      carName === department
    );
  }
}
