import { Injectable, Logger } from '@nestjs/common';
import {
  ApprovalState,
  Prisma,
  TicketValidationState
} from '@prisma/client';
import { differenceInBusinessDays } from 'date-fns';
import { PrismaService } from 'src/core/database/prisma.service';

@Injectable()
export class TicketRepository {
  private logger = new Logger(TicketRepository.name);

  constructor(private readonly prisma: PrismaService) {}

  async calculateTicketStateMeta(ticketState: TicketValidationState) {
    const ticketWithCurrentStateAndTours: Prisma.TicketWhereInput = {
      currentState: ticketState,
      tours: { some: { check: 0 } },
    };
    const [
      count,
      approvalRequiredCount,
      approvalUnknownCount,
      tdNotCompanyCount,
      approvalNotCompanyCount,
    ] = await this.prisma.$transaction([
      this.prisma.ticket.count({
        where: { ...ticketWithCurrentStateAndTours },
      }),
      this.prisma.ticket.aggregate({
        _count: {
          id: true,
        },
        where: {
          ...ticketWithCurrentStateAndTours,
          approvalState: ApprovalState.REQUIRED,
        },
      }),
      this.prisma.ticket.aggregate({
        _count: {
          id: true,
        },
        where: {
          ...ticketWithCurrentStateAndTours,
          approvalState: ApprovalState.UNKNOWN,
        },
      }),
      this.prisma.ticket.aggregate({
        _count: {
          id: true,
        },
        where: {
          ...ticketWithCurrentStateAndTours,
          documentInfo: {
            path: ['approval', 'location'],
            not: 'company',
          },
        },
      }),
      this.prisma.ticket.aggregate({
        _count: {
          id: true,
        },
        where: {
          ...ticketWithCurrentStateAndTours,
          documentInfo: {
            path: ['tdLocation'],
            not: 'company',
          },
        },
      }),
    ]);

    return {
      count,
      approvalRequiredCount: approvalRequiredCount._count.id,
      approvalUnknownCount: approvalUnknownCount._count.id,
      tdNotCompanyCount: tdNotCompanyCount._count.id,
      approvalNotCompanyCount: approvalNotCompanyCount._count.id,
    };
  }

  async calculateTicketStateKeyFigures(ticketState: TicketValidationState) {
    const ticketWithCurrentStateAndTours: Prisma.TicketWhereInput = {
      currentState: ticketState,
      tours: { some: { check: 0 } },
    };

    const ticketWithState = await this.prisma.ticket.findMany({
      where: { ...ticketWithCurrentStateAndTours },
      include: {
        state: true,
      },
    });

    const dwellTimesForTicketState = ticketWithState
      .map(({ state }) => {
        const stateToCalculateIdx = state.findIndex(
          ({ state }) => state === ticketState,
        );
        if (stateToCalculateIdx > -1 && state[stateToCalculateIdx + 1]) {
          const nextState = state[stateToCalculateIdx + 1];
          return differenceInBusinessDays(
            new Date(nextState.createdAt),
            new Date(state[stateToCalculateIdx].createdAt),
          );
        } else if (stateToCalculateIdx > -1) {
          return differenceInBusinessDays(
            new Date(),
            new Date(state[stateToCalculateIdx].createdAt),
          );
        } else {
          return undefined;
        }
      })
      .filter(Boolean);

    return {
      dwellTime:
        dwellTimesForTicketState.reduce((a, b) => a + b, 0) /
        dwellTimesForTicketState.length,
    };
  }
}
