import { Injectable, NotFoundException, BadRequestException } from '@nestjs/common';
import { PrismaService } from '../../common/prisma.service';
import { CreateTrainDto, CreateCoachDto, UpdateCoachDto, AssignCoachDto, ListCoachesDto, CreateCoachTypeDto, UpdateCoachTypeDto, CreateClassDto, UpdateClassDto, GenerateSeatMapDto } from './fleet.dto';
import { SeatKind } from '@prisma/client';
import { DeleteOperationException } from '../../common/exceptions/delete-operation.exception';
import { AuditService } from '../../common/audit.service';

// Parses '2+2' → [2, 2], '2+2+2' → [2, 2, 2]
function parseArrangement(arrangement: string): number[] {
  return arrangement.split('+').map((n) => parseInt(n, 10));
}

// Derives column labels from arrangement: '2+2' → ['A','B','C','D']
function seatCols(arrangement: string): string[] {
  const groups = parseArrangement(arrangement);
  const total = groups.reduce((s, n) => s + n, 0);
  return Array.from({ length: total }, (_, i) => String.fromCharCode(65 + i));
}

// Returns true if column is a window seat
function isWindowCol(colIndex: number, groups: number[]): boolean {
  const total = groups.reduce((s, n) => s + n, 0);
  return colIndex === 0 || colIndex === total - 1;
}

// Returns true if column is an aisle seat
function isAisleCol(colIndex: number, groups: number[]): boolean {
  let cursor = 0;
  for (const g of groups) {
    cursor += g;
    const leftAisle = cursor - 1;
    const rightAisle = cursor;
    if (colIndex === leftAisle || colIndex === rightAisle) return true;
  }
  return false;
}

type BedCategory = 'ECONOMY_BED' | 'VIP_BED' | null;

// Default beds per room for each category when not explicitly configured
const DEFAULT_BEDS_PER_ROOM: Record<'ECONOMY_BED' | 'VIP_BED', number> = {
  VIP_BED: 4,
  ECONOMY_BED: 6,
};

// Name-based fallback: checks if 'vip' is present for any bed coach type
function detectBedCategory(coachTypeName: string): BedCategory {
  const name = coachTypeName.toLowerCase();
  const isBed = name.includes('bed') || name.includes('berth') || name.includes('sleeper') || name.includes('couchette');
  if (!isBed) return null;
  if (name.includes('vip')) return 'VIP_BED';
  return 'ECONOMY_BED';
}

// Resolves bed type names per side from beds-per-side count:
// 2/side → ['LOWER','UPPER']  (VIP style)
// 3/side → ['LOWER','MIDDLE','UPPER']  (Economy style)
function resolveBedTypes(bedsPerSide: number): string[] {
  if (bedsPerSide === 1) return ['LOWER'];
  if (bedsPerSide === 2) return ['LOWER', 'UPPER'];
  if (bedsPerSide === 3) return ['LOWER', 'MIDDLE', 'UPPER'];
  return Array.from({ length: bedsPerSide }, (_, i) => {
    if (i === 0) return 'LOWER';
    if (i === bedsPerSide - 1) return 'UPPER';
    return 'MIDDLE';
  });
}

// Generates the flat seat/bed list for a bed coach.
// Row = room number; col = position-relative label (L1, L2 … R1, R2 …).
function buildBedSeats(
  coachId: string,
  capacity: number,
  bedsPerRoom: number,
): SeatRow[] {
  const bedsPerSide = bedsPerRoom / 2;
  const bedTypeNames = resolveBedTypes(bedsPerSide);
  const layout: Array<{ position: 'LEFT' | 'RIGHT'; bedType: string }> = [
    ...bedTypeNames.map(bt => ({ position: 'LEFT'  as const, bedType: bt })),
    ...bedTypeNames.map(bt => ({ position: 'RIGHT' as const, bedType: bt })),
  ];

  const roomCount = Math.ceil(capacity / bedsPerRoom);
  const seats: SeatRow[] = [];
  let seatNumber = 1;

  for (let room = 1; room <= roomCount; room++) {
    const posCount: Record<string, number> = {};
    for (let slot = 0; slot < bedsPerRoom && seats.length < capacity; slot++) {
      const { position, bedType } = layout[slot];
      posCount[position] = (posCount[position] ?? 0) + 1;
      const col = `${position[0]}${posCount[position]}`;
      seats.push({
        coachId,
        row: room,
        col,
        seatNumber: `${seatNumber}`,
        kind: SeatKind.STANDARD,
        bedPosition: bedType.toLowerCase(),
        isWindow: false,
        isAisle: false,
      });
      seatNumber++;
    }
  }
  return seats;
}

function buildRegularSeats(coachId: string, arrangement: string, capacity: number): SeatRow[] {
  const cols = seatCols(arrangement);
  const groups = parseArrangement(arrangement);
  const seats: SeatRow[] = [];
  let row = 1;
  let seatNumber = 1;
  let seatIndex = 0;

  while (seatIndex < capacity) {
    for (let ci = 0; ci < cols.length && seatIndex < capacity; ci++) {
      const col = cols[ci];
      seats.push({
        coachId,
        row,
        col,
        seatNumber: `${seatNumber}`,
        kind: SeatKind.STANDARD,
        bedPosition: null,
        isWindow: isWindowCol(ci, groups),
        isAisle: isAisleCol(ci, groups),
      });
      seatNumber++;
      seatIndex++;
    }
    row++;
  }
  return seats;
}

type SeatRow = {
  coachId: string;
  row: number;
  col: string;
  seatNumber: string;
  kind: SeatKind;
  bedPosition?: string | null;
  isWindow?: boolean;
  isAisle?: boolean;
};

@Injectable()
export class FleetService {
  constructor(private prisma: PrismaService, private auditService: AuditService) {}

  async createCoachType(dto: CreateCoachTypeDto) {
    return this.prisma.coachType.create({
      data: {
        code: dto.code,
        name: dto.name,
        type: dto.type || 'passenger',
      },
      include: {
        seatClasses: true,
        coaches: true,
      },
    });
  }

  async getCoachTypes() {
    return this.prisma.coachType.findMany({
      include: {
        seatClasses: true,
        coaches: true,
      },
      orderBy: { createdAt: 'desc' },
    });
  }

  async updateCoachType(id: string, dto: UpdateCoachTypeDto) {
    const coachType = await this.prisma.coachType.findUnique({ where: { id } });
    if (!coachType) throw new NotFoundException('Coach type not found');
    
    const data: any = {};
    if (dto.code !== undefined) data.code = dto.code;
    if (dto.name !== undefined) data.name = dto.name;
    if (dto.type !== undefined) data.type = dto.type;
    
    return this.prisma.coachType.update({
      where: { id },
      data,
      include: {
        seatClasses: true,
        coaches: true,
      },
    });
  }

  async deleteCoachType(id: string) {
    const coachType = await this.prisma.coachType.findUnique({ 
      where: { id },
      include: {
        coaches: true,
        seatClasses: true,
      },
    });
    if (!coachType) throw new NotFoundException('Coach type not found');
    
    const constraints = [];
    if (coachType.coaches.length > 0) {
      constraints.push({
        entityName: 'coach',
        count: coachType.coaches.length,
        action: 'reassign' as const
      });
    }
    
    if (coachType.seatClasses.length > 0) {
      constraints.push({
        entityName: 'seat class',
        count: coachType.seatClasses.length,
        action: 'reassign' as const
      });
    }
    
    if (constraints.length > 0) {
      throw new DeleteOperationException('Coach Type', coachType.name, constraints);
    }
    
    return this.prisma.coachType.delete({ where: { id } });
  }

  async createClass(dto: CreateClassDto) {
    return this.prisma.seatClass.create({
      data: {
        coachTypeId: dto.coachTypeId,
        name: dto.name,
        description: dto.description,
        baseFareMinor: dto.baseFareMinor,
        ...(dto.premiumMinor !== undefined && { premiumMinor: dto.premiumMinor }),
        ...(dto.insuranceFeeMinor !== undefined && { insuranceFeeMinor: dto.insuranceFeeMinor }),
        ...(dto.isActive !== undefined && { isActive: dto.isActive }),
      },
    });
  }

  async getClasses(coachTypeId?: string) {
    const where = coachTypeId ? { coachTypeId } : {};
    return this.prisma.seatClass.findMany({
      where,
      include: { coachType: true },
      orderBy: { createdAt: 'desc' },
    });
  }

  async updateClass(id: string, dto: UpdateClassDto) {
    const seatClass = await this.prisma.seatClass.findUnique({ where: { id } });
    if (!seatClass) throw new NotFoundException('Seat class not found');
    
    const updateData: any = {
      coachTypeId: dto.coachTypeId,
      name: dto.name,
      description: dto.description,
      baseFareMinor: dto.baseFareMinor,
      premiumMinor: dto.premiumMinor,
      insuranceFeeMinor: dto.insuranceFeeMinor,
    };
    
    if (dto.isActive !== undefined) {
      updateData.isActive = dto.isActive;
    }
    
    return this.prisma.seatClass.update({
      where: { id },
      data: updateData,
      include: { coachType: true },
    });
  }

  async deleteClass(id: string, cascade = false) {
    const seatClass = await this.prisma.seatClass.findUnique({ 
      where: { id },
      include: {
        fareRules: true,
        routeFareRules: true,
        segmentFares: true,
      },
    });
    if (!seatClass) throw new NotFoundException('Seat class not found');
    
    if (!cascade) {
      const totalFareRules = seatClass.fareRules.length + seatClass.routeFareRules.length + seatClass.segmentFares.length;
      const constraints = [];
      
      if (totalFareRules > 0) {
        constraints.push({
          entityName: 'fare rule',
          count: totalFareRules,
          action: 'delete' as const
        });
      }
      
      if (constraints.length > 0) {
        throw new DeleteOperationException('Seat Class', seatClass.name, constraints);
      }
    }

    if (cascade) {
      await this.prisma.fareRule.deleteMany({ where: { seatClassId: id } });
      await this.prisma.routeFareRule.deleteMany({ where: { seatClassId: id } });
      await this.prisma.segmentFareRule.deleteMany({ where: { seatClassId: id } });
    }
    
    return this.prisma.seatClass.delete({ where: { id } });
  }

  createSeatClass(dto: CreateClassDto) {
    return this.createClass(dto);
  }

  getSeatClasses(coachTypeId?: string) {
    return this.getClasses(coachTypeId);
  }

  async updateSeatClass(id: string, dto: UpdateClassDto) {
    return this.updateClass(id, dto);
  }

  async deleteSeatClass(id: string) {
    return this.deleteClass(id);
  }

  getTrains() {
    return this.prisma.train.findMany({
      where: { isActive: true },
      include: { schedules: { take: 5, orderBy: { departureAt: 'desc' } } },
    });
  }

  async createTrain(dto: CreateTrainDto) {
    const train = await this.prisma.train.create({
      data: {
        number: dto.number,
        name: dto.name,
        operatorId: dto.operatorId,
        operatorName: dto.operatorName,
        description: dto.description,
        isActive: dto.isActive ?? true,
      },
    });
    await this.auditService.log({ action: 'CREATE', entityType: 'Train', entityId: train.id, newData: { number: train.number, name: train.name } });
    return train;
  }

  async updateTrain(id: string, dto: CreateTrainDto) {
    const train = await this.prisma.train.findUnique({ where: { id } });
    if (!train) throw new NotFoundException('Train not found');
    const updated = await this.prisma.train.update({
      where: { id },
      data: {
        number: dto.number,
        name: dto.name,
        operatorId: dto.operatorId,
        operatorName: dto.operatorName,
        description: dto.description,
        ...(dto.isActive !== undefined && { isActive: dto.isActive }),
      },
    });
    await this.auditService.log({ action: 'UPDATE', entityType: 'Train', entityId: id, newData: { number: dto.number, name: dto.name } });
    return updated;
  }

  async deleteTrain(id: string, cascade = false) {
    const train = await this.prisma.train.findUnique({ 
      where: { id },
      include: { schedules: true },
    });
    if (!train) throw new NotFoundException('Train not found');
    
    if (!cascade) {
      const constraints = [];
      if (train.schedules.length > 0) {
        constraints.push({
          entityName: 'schedule',
          count: train.schedules.length,
          action: 'delete' as const
        });
      }
      
      if (constraints.length > 0) {
        throw new DeleteOperationException('Train', `${train.number} (${train.name})`, constraints);
      }
    }

    if (cascade && train.schedules.length > 0) {
      const scheduleIds = train.schedules.map((s: any) => s.id);
      await this.prisma.tripStopTime.deleteMany({ where: { scheduleId: { in: scheduleIds } } });
      await this.prisma.coachAssignment.deleteMany({ where: { scheduleId: { in: scheduleIds } } });
      await this.prisma.tripLiveStatus.deleteMany({ where: { scheduleId: { in: scheduleIds } } });
      await this.prisma.menuItem.deleteMany({ where: { scheduleId: { in: scheduleIds } } });
      await this.prisma.journeySegment.deleteMany({ where: { scheduleId: { in: scheduleIds } } });

      const bookings = await this.prisma.booking.findMany({
        where: { OR: [{ scheduleId: { in: scheduleIds } }, { returnScheduleId: { in: scheduleIds } }] },
        select: { id: true },
      });
      if (bookings.length > 0) {
        const bookingIds = bookings.map(b => b.id);
        const tickets = await this.prisma.ticket.findMany({ where: { bookingId: { in: bookingIds } }, select: { id: true } });
        if (tickets.length > 0) {
          await this.prisma.gateValidationLog.deleteMany({ where: { ticketId: { in: tickets.map(t => t.id) } } });
        }
        await this.prisma.ticket.deleteMany({ where: { bookingId: { in: bookingIds } } });
        const foodOrders = await this.prisma.foodOrder.findMany({ where: { bookingId: { in: bookingIds } }, select: { id: true } });
        if (foodOrders.length > 0) {
          await this.prisma.foodOrderItem.deleteMany({ where: { orderId: { in: foodOrders.map(o => o.id) } } });
        }
        await this.prisma.foodOrder.deleteMany({ where: { bookingId: { in: bookingIds } } });
        const paymentIntents = await this.prisma.paymentIntent.findMany({ where: { bookingId: { in: bookingIds } }, select: { id: true } });
        if (paymentIntents.length > 0) {
          await this.prisma.paymentRefund.deleteMany({ where: { paymentIntentId: { in: paymentIntents.map(p => p.id) } } });
        }
        await this.prisma.paymentIntent.deleteMany({ where: { bookingId: { in: bookingIds } } });
        await this.prisma.bookingSeat.deleteMany({ where: { bookingId: { in: bookingIds } } });
        await this.prisma.agentBooking.deleteMany({ where: { bookingId: { in: bookingIds } } });
        await this.prisma.bookingModification.deleteMany({ where: { bookingId: { in: bookingIds } } });
        await this.prisma.bookingCancellation.deleteMany({ where: { bookingId: { in: bookingIds } } });
        await this.prisma.baggageBooking.deleteMany({ where: { bookingId: { in: bookingIds } } });
        await this.prisma.excessBaggageCharge.deleteMany({ where: { bookingId: { in: bookingIds } } });
        await this.prisma.journey.deleteMany({ where: { bookingId: { in: bookingIds } } });
        await this.prisma.booking.deleteMany({ where: { id: { in: bookingIds } } });
      }

      const packages = await this.prisma.travelPackage.findMany({
        where: { OR: [{ outboundScheduleId: { in: scheduleIds } }, { returnScheduleId: { in: scheduleIds } }] },
        select: { id: true },
      });
      if (packages.length > 0) {
        const packageIds = packages.map(p => p.id);
        await this.prisma.packagePriceTier.deleteMany({ where: { packageId: { in: packageIds } } });
        await this.prisma.travelPackage.deleteMany({ where: { id: { in: packageIds } } });
      }

      await this.prisma.trainSchedule.deleteMany({ where: { id: { in: scheduleIds } } });
    }
    
    const deleted = await this.prisma.train.delete({ where: { id } });
    await this.auditService.log({ action: 'DELETE', entityType: 'Train', entityId: id, oldData: { number: train.number, name: train.name } });
    return deleted;
  }

  async restoreTrain(id: string) {
    const train = await this.prisma.train.findUnique({ where: { id } });
    if (!train) throw new NotFoundException('Train not found');
    return this.prisma.train.update({ where: { id }, data: { isActive: true } });
  }

  async getCoach(id: string) {
    const coach = await this.prisma.coach.findUnique({
      where: { id },
      include: {
        coachType: true,
        seats: { orderBy: [{ row: 'asc' }, { col: 'asc' }] },
        assignments: {
          include: { schedule: { include: { originStation: true, destinationStation: true } } },
          orderBy: { schedule: { departureAt: 'desc' } },
          take: 5,
        },
      },
    });
    if (!coach) throw new NotFoundException('Coach not found');
    return coach;
  }

  async listCoaches(dto: ListCoachesDto) {
    const where: any = {};
    if (dto.status) where.status = dto.status;
    if (dto.scheduleId) where.assignments = { some: { scheduleId: dto.scheduleId } };

    return this.prisma.coach.findMany({
      where,
      include: { coachType: true },
      orderBy: { sequence: 'asc' },
    });
  }

  async createCoach(dto: CreateCoachDto) {
    const groups = parseArrangement(dto.arrangement);
    if (groups.some(isNaN)) {
      throw new BadRequestException(`Invalid arrangement format "${dto.arrangement}". Use e.g. "2+2"`);
    }

    // Use user-provided sequence or auto-assign the next one
    let resolvedSequence = dto.sequence;
    if (resolvedSequence === undefined || resolvedSequence === null) {
      const lastCoach = await this.prisma.coach.findFirst({
        orderBy: { sequence: 'desc' },
      });
      resolvedSequence = (lastCoach?.sequence ?? 0) + 1;
    }

    const coach = await this.prisma.coach.create({
      data: {
        coachTypeId: dto.coachTypeId,
        number: dto.number,
        sequence: resolvedSequence,
        arrangement: dto.arrangement,
        capacity: dto.capacity,
        status: dto.status || 'ACTIVE',
      },
      include: { coachType: true },
    });

    if (dto.capacity > 0) {
      // dto.bedCategory takes priority; fall back to name-based detection
      const bedCategory: BedCategory = dto.bedCategory ?? detectBedCategory(coach.coachType?.name || '');
      let seats: SeatRow[];

      if (bedCategory) {
        const bedsPerRoom = dto.bedsPerRoom ?? DEFAULT_BEDS_PER_ROOM[bedCategory];
        if (bedsPerRoom < 2 || bedsPerRoom % 2 !== 0) {
          throw new BadRequestException('bedsPerRoom must be an even number ≥ 2');
        }
        seats = buildBedSeats(coach.id, dto.capacity, bedsPerRoom);
      } else {
        seats = buildRegularSeats(coach.id, dto.arrangement, dto.capacity);
      }

      await this.prisma.seat.createMany({ data: seats });
    }

    await this.auditService.log({ action: 'CREATE', entityType: 'Coach', entityId: coach.id, newData: { number: coach.number, capacity: coach.capacity } });
    return coach;
  }

  async updateCoach(id: string, dto: UpdateCoachDto) {
    const coach = await this.prisma.coach.findUnique({ where: { id } });
    if (!coach) throw new NotFoundException('Coach not found');
    
    const updated = await this.prisma.coach.update({ 
      where: { id }, 
      data: {
        number: dto.number,
        arrangement: dto.arrangement,
        capacity: dto.capacity,
        status: dto.status,
        sequence: dto.sequence,
      },
      include: { coachType: true },
    });
    await this.auditService.log({ action: 'UPDATE', entityType: 'Coach', entityId: id, newData: { number: dto.number, status: dto.status } });
    return updated;
  }

  async deleteCoach(id: string, cascade = false) {
    const coach = await this.prisma.coach.findUnique({ 
      where: { id },
      include: {
        assignments: true,
        seats: {
          include: {
            bookingSeats: true,
            blocks: true,
            tickets: true,
          },
        },
      },
    });
    if (!coach) throw new NotFoundException('Coach not found');
    
    if (!cascade) {
      const constraints = [];
      
      if ((coach as any).assignments.length > 0) {
        constraints.push({
          entityName: 'schedule assignment',
          count: (coach as any).assignments.length,
          action: 'reassign' as const
        });
      }
      
      const bookedSeats = (coach as any).seats.filter((seat: any) => seat.bookingSeats.length > 0);
      if (bookedSeats.length > 0) {
        constraints.push({
          entityName: 'booked seat',
          count: bookedSeats.length,
          action: 'complete' as const
        });
      }
      
      const blockedSeats = (coach as any).seats.filter((seat: any) => seat.blocks.length > 0);
      if (blockedSeats.length > 0) {
        constraints.push({
          entityName: 'blocked seat',
          count: blockedSeats.length,
          action: 'delete' as const
        });
      }
      
      const seatsWithTickets = (coach as any).seats.filter((seat: any) => seat.tickets.length > 0);
      if (seatsWithTickets.length > 0) {
        constraints.push({
          entityName: 'seat with issued ticket',
          count: seatsWithTickets.length,
          action: 'complete' as const
        });
      }
      
      if (constraints.length > 0) {
        throw new DeleteOperationException('Coach', coach.number, constraints);
      }
    }
    
    if (cascade) {
      const seatIds = (coach as any).seats.map((s: any) => s.id);
      if (seatIds.length > 0) {
        await this.prisma.bookingSeat.deleteMany({ where: { seatId: { in: seatIds } } });
        await this.prisma.seatBlock.deleteMany({ where: { seatId: { in: seatIds } } });
        await this.prisma.ticket.deleteMany({ where: { seatId: { in: seatIds } } });
      }
      await this.prisma.coachAssignment.deleteMany({ where: { coachId: id } });
      await this.prisma.routeCoachTemplate.deleteMany({ where: { coachId: id } });
    }

    await this.prisma.seat.deleteMany({ where: { coachId: id } });
    
    const deleted = await this.prisma.coach.delete({ where: { id } });
    await this.auditService.log({ action: 'DELETE', entityType: 'Coach', entityId: id, oldData: { number: coach.number } });
    return deleted;
  }

  async assignCoach(dto: AssignCoachDto) {
    const [schedule, coach] = await Promise.all([
      this.prisma.trainSchedule.findUnique({ where: { id: dto.scheduleId } }),
      this.prisma.coach.findUnique({ where: { id: dto.coachId } }),
    ]);
    if (!schedule) throw new NotFoundException('Schedule not found');
    if (!coach) throw new NotFoundException('Coach not found');
    if (coach.status !== 'ACTIVE') throw new BadRequestException('Coach is not active');
    return this.prisma.coachAssignment.create({ data: dto });
  }

  async removeAssignment(id: string) {
    const assignment = await this.prisma.coachAssignment.findUnique({ where: { id } });
    if (!assignment) throw new NotFoundException('Assignment not found');
    return this.prisma.coachAssignment.delete({ where: { id } });
  }

  async generateSeatMapPreview(dto: GenerateSeatMapDto) {
    const { coachCount, roomsPerCoach, roomType } = dto;
    const bedsPerRoom = DEFAULT_BEDS_PER_ROOM[roomType];
    const bedTypeNames = resolveBedTypes(bedsPerRoom / 2);
    const layout: Array<{ position: 'LEFT' | 'RIGHT'; bedType: string }> = [
      ...bedTypeNames.map(bt => ({ position: 'LEFT'  as const, bedType: bt })),
      ...bedTypeNames.map(bt => ({ position: 'RIGHT' as const, bedType: bt })),
    ];
    const seats: object[] = [];
    let globalSeq = 1;

    for (let c = 1; c <= coachCount; c++) {
      const coachLabel = `C${c}`;
      for (let r = 1; r <= roomsPerCoach; r++) {
        const roomLabel = `R${r}`;
        const posCount: Record<string, number> = {};
        for (let s = 0; s < bedsPerRoom; s++) {
          const { position, bedType } = layout[s];
          posCount[position] = (posCount[position] ?? 0) + 1;
          seats.push({
            seat_id: `${coachLabel}-${roomLabel}-S${globalSeq}`,
            coach_id: coachLabel,
            room_id: `${coachLabel}-${roomLabel}`,
            category: roomType,
            position,
            col: `${position[0]}${posCount[position]}`,
            bed_type: bedType,
            sequence_number: globalSeq,
            status: 'AVAILABLE',
          });
          globalSeq++;
        }
      }
    }
    return {
      coachCount,
      roomsPerCoach,
      roomType,
      bedsPerRoom,
      totalBeds: seats.length,
      seats,
    };
  }

  async getCoachUtilization() {
    const coaches = await this.prisma.coach.findMany({
      include: {
        coachType: true,
        seats: { select: { id: true, status: true } },
        assignments: {
          include: {
            schedule: {
              select: { id: true, departureAt: true, status: true, _count: { select: { bookings: true } } },
            },
          },
          orderBy: { schedule: { departureAt: 'desc' } },
          take: 10,
        },
      },
      orderBy: { sequence: 'asc' },
    });

    return coaches.map((coach) => {
      const totalSeats = coach.seats.length;
      const bookedSeats = coach.seats.filter((s) => s.status === 'BOOKED').length;
      const blockedSeats = coach.seats.filter((s) => s.status === 'BLOCKED').length;
      const maintenanceSeats = coach.seats.filter((s) => (s.status as string) === 'UNDER_MAINTENANCE').length;
      const availableSeats = coach.seats.filter((s) => s.status === 'AVAILABLE').length;
      const totalAssignments = coach.assignments.length;
      const totalBookings = coach.assignments.reduce((sum, a) => sum + ((a.schedule as any)._count?.bookings ?? 0), 0);
      const utilizationRate = totalSeats > 0 ? +((bookedSeats / totalSeats) * 100).toFixed(2) : 0;

      return {
        id: coach.id,
        number: coach.number,
        sequence: coach.sequence,
        coachType: coach.coachType?.name,
        status: coach.status,
        totalSeats,
        availableSeats,
        bookedSeats,
        blockedSeats,
        maintenanceSeats,
        utilizationRate,
        totalAssignments,
        totalBookings,
        recentSchedules: coach.assignments.slice(0, 5).map((a) => ({
          scheduleId: a.scheduleId,
          departureAt: a.schedule.departureAt,
          scheduleStatus: a.schedule.status,
          bookings: (a.schedule as any)._count?.bookings ?? 0,
        })),
      };
    });
  }

  async getAnalytics() {
    const [totalTrains, totalSchedules, totalSeats, bookedSeats] = await Promise.all([
      this.prisma.train.count(),
      this.prisma.trainSchedule.count(),
      this.prisma.seat.count(),
      this.prisma.seat.count({ where: { status: 'BOOKED' } }),
    ]);
    return {
      totalTrains,
      totalSchedules,
      totalSeats,
      bookedSeats,
      occupancyRate: totalSeats > 0 ? +((bookedSeats / totalSeats) * 100).toFixed(2) : 0,
    };
  }
}
