import { Injectable } from '@nestjs/common';
import { PrismaService } from '../../common/prisma.service';
import { EnhancedSeatsService } from './enhanced-seats.service';
import { EventEmitter2, OnEvent } from '@nestjs/event-emitter';
import { Cron, CronExpression } from '@nestjs/schedule';

@Injectable()
export class TripProgressService {
  constructor(
    private prisma: PrismaService,
    private enhancedSeatsService: EnhancedSeatsService,
    private eventEmitter: EventEmitter2
  ) {}

  /**
   * Update trip progress and trigger seat releases
   */
  async updateTripProgress(tripId: string, currentStationId: string, progressPercent: number) {
    return this.prisma.$transaction(async (tx) => {
      // 1. Update trip live status
      await tx.tripLiveStatus.upsert({
        where: { scheduleId: tripId },
        update: {
          currentLocationLabel: currentStationId,
          progressPercent,
          updatedAt: new Date()
        },
        create: {
          scheduleId: tripId,
          state: 'EN_ROUTE',
          currentLocationLabel: currentStationId,
          progressPercent,
          delayMinutes: 0,
          updatedAt: new Date()
        }
      });

      // 2. Get station name for comparison
      const station = await tx.station.findUnique({
        where: { id: currentStationId }
      });

      if (station) {
        // 3. Trigger seat release for passengers reaching destination
        const releaseResult = await this.enhancedSeatsService.releaseSeats(tripId, currentStationId);

        // 4. Emit progress update event
        this.eventEmitter.emit('trip.progress.updated', {
          tripId,
          currentStation: station.name,
          progressPercent,
          releasedSeats: releaseResult.releasedSeats
        });

        return {
          tripId,
          currentStation: station.name,
          progressPercent,
          releasedSeats: releaseResult.releasedSeats.length,
          updatedAt: new Date()
        };
      }

      return { tripId, currentStation: currentStationId, progressPercent, releasedSeats: 0 };
    });
  }

  /**
   * Simulate trip progress (for testing/demo)
   */
  async simulateTripProgress(tripId: string) {
    const trip = await this.prisma.trainSchedule.findUnique({
      where: { id: tripId },
      include: {
        stopTimes: {
          include: { station: true },
          orderBy: { sequence: 'asc' }
        }
      }
    });

    if (!trip) {
      throw new Error('Trip not found');
    }

    // Simulate progress through each station
    for (let i = 0; i < trip.stopTimes.length; i++) {
      const stopTime = trip.stopTimes[i];
      const progressPercent = Math.round((i / (trip.stopTimes.length - 1)) * 100);

      await this.updateTripProgress(tripId, stopTime.stationId, progressPercent);

      // Emit station arrival event
      this.eventEmitter.emit('trip.station.arrived', {
        tripId,
        stationId: stopTime.stationId,
        stationName: stopTime.station.name,
        sequence: stopTime.sequence,
        progressPercent
      });

      // Wait 30 seconds between stations (for demo)
      await new Promise(resolve => setTimeout(resolve, 30000));
    }
  }

  /**
   * Handle trip completion
   */
  @OnEvent('trip.completed')
  async handleTripCompleted(payload: { tripId: string }) {
    // Release all remaining seats for this trip
    const trip = await this.prisma.trainSchedule.findUnique({
      where: { id: payload.tripId },
      include: {
        coachAssignments: {
          include: {
            coach: {
              include: {
                seats: {
                  where: { status: 'BOOKED' }
                }
              }
            }
          }
        }
      }
    });

    if (trip) {
      const bookedSeatIds = trip.coachAssignments.flatMap(assignment =>
        assignment.coach.seats.map(seat => seat.id)
      );

      if (bookedSeatIds.length > 0) {
        await this.prisma.seat.updateMany({
          where: { id: { in: bookedSeatIds } },
          data: { status: 'AVAILABLE' }
        });

        this.eventEmitter.emit('trip.seats.released', {
          tripId: payload.tripId,
          releasedSeats: bookedSeatIds
        });
      }
    }
  }

  /**
   * Background job to expire holds every minute
   */
  @Cron(CronExpression.EVERY_MINUTE)
  async expireHoldsJob() {
    try {
      const result = await this.enhancedSeatsService.expireHolds();
      if (result.expiredHolds > 0) {
        console.log(`Expired ${result.expiredHolds} holds, released ${result.releasedSeats.length} seats`);
      }
    } catch (error) {
      console.error('Error expiring holds:', error);
    }
  }

  /**
   * Get current trip status with seat availability
   */
  async getTripStatus(tripId: string) {
    const trip = await this.prisma.trainSchedule.findUnique({
      where: { id: tripId },
      include: {
        liveStatus: true,
        stopTimes: {
          include: { station: true },
          orderBy: { sequence: 'asc' }
        },
        coachAssignments: {
          include: {
            coach: {
              include: { seats: true }
            }
          }
        }
      }
    });

    if (!trip) {
      throw new Error('Trip not found');
    }

    const seatSummary = {
      total: 0,
      available: 0,
      held: 0,
      booked: 0,
      blocked: 0
    };

    trip.coachAssignments.forEach(assignment => {
      assignment.coach.seats.forEach(seat => {
        seatSummary.total++;
        const status = seat.status.toLowerCase() as keyof typeof seatSummary;
        if (status in seatSummary) {
          seatSummary[status]++;
        }
      });
    });

    return {
      tripId,
      status: trip.status,
      currentLocation: trip.liveStatus?.currentLocationLabel,
      progressPercent: trip.liveStatus?.progressPercent || 0,
      delayMinutes: trip.liveStatus?.delayMinutes || 0,
      stations: trip.stopTimes.map(st => ({
        id: st.stationId,
        name: st.station.name,
        sequence: st.sequence,
        plannedArrival: st.plannedArrivalAt,
        plannedDeparture: st.plannedDepartureAt,
        actualArrival: st.actualArrivalAt
      })),
      seatSummary,
      lastUpdated: trip.liveStatus?.updatedAt
    };
  }
}