import { Body, Controller, Delete, Get, Param, Post, Patch, UseGuards, Query, Req, BadRequestException } from '@nestjs/common';
import { ApiTags, ApiOperation, ApiBearerAuth, ApiResponse, ApiQuery, ApiBody } from '@nestjs/swagger';
import { BookingsService } from './bookings.service';
import { GuestBookingService } from './guest-booking.service';
import { CreateBookingDto, ModifyBookingDto, CancelBookingDto } from './bookings.dto';
import { CreateGuestBookingDto, GetSavedPassengersDto } from './guest-booking.dto';
import { JwtGuard } from '../../common/jwt.guard';
import { IamGuard } from '../../common/iam-adapter';

@ApiTags('Booking')
@Controller('bookings')
export class BookingsController {
  constructor(
    private service: BookingsService,
    private guestService: GuestBookingService,
  ) {}
  
  @Get('my')
  @UseGuards(JwtGuard)
  @ApiBearerAuth('JWT-auth')
  @ApiOperation({ 
    summary: 'Get logged-in user\'s booking history',
    description: 'Returns all bookings for the authenticated user with schedule and payment details'
  })
  @ApiQuery({ name: 'search', required: false, description: 'Search by booking reference or station names' })
  @ApiQuery({ name: 'status', required: false, description: 'Filter by booking status' })
  @ApiQuery({ name: 'page', required: false, description: 'Page number' })
  @ApiQuery({ name: 'pageSize', required: false, description: 'Items per page' })
  @ApiResponse({ status: 200, description: 'List of user bookings with schedule and passenger details' })
  getMyBookings(
    @Req() req: any,
    @Query('search') search?: string,
    @Query('status') status?: string,
    @Query('page') page?: string,
    @Query('pageSize') pageSize?: string,
  ) {
    const passengerId = req.user?.passengerId;
    if (!passengerId) throw new Error('Passenger ID not found in token');
    return this.service.findByPassengerId(passengerId, { 
      search, 
      status, 
      page: page ? parseInt(page) : 1, 
      pageSize: pageSize ? parseInt(pageSize) : 20 
    });
  }

  @Get('by-device')
  @ApiOperation({ 
    summary: 'Get bookings by device ID',
    description: 'Returns all bookings associated with a device ID (for guest users). Includes saved passenger details and booking history.'
  })
  @ApiQuery({ name: 'deviceId', required: true, description: 'Device identifier' })
  @ApiQuery({ name: 'search', required: false, description: 'Search by booking reference or station names' })
  @ApiQuery({ name: 'status', required: false, description: 'Filter by booking status' })
  @ApiQuery({ name: 'page', required: false, description: 'Page number' })
  @ApiQuery({ name: 'pageSize', required: false, description: 'Items per page' })
  @ApiResponse({ status: 200, description: 'List of guest bookings and saved passengers for device' })
  @ApiResponse({ status: 400, description: 'Device ID is required' })
  getByDevice(
    @Query('deviceId') deviceId?: string,
    @Query('search') search?: string,
    @Query('status') status?: string,
    @Query('page') page?: string,
    @Query('pageSize') pageSize?: string,
  ) {
    if (!deviceId) throw new BadRequestException('Device ID is required');
    return this.service.findByDeviceId(deviceId, { 
      search, 
      status, 
      page: page ? parseInt(page) : 1, 
      pageSize: pageSize ? parseInt(pageSize) : 20 
    });
  }
  
  @Get()
  @ApiOperation({ 
    summary: 'List all bookings with filters (Admin/Agent)',
    description: 'Returns paginated list of bookings. Use `returnLegStatus=OUTBOUND_ONLY` to find round-trip no-shows on the return leg, `INBOUND_ONLY` for passengers who only used the return leg, `BOTH_USED` for fully completed round-trips, and `NEITHER_USED` for confirmed but not yet boarded.'
  })
  @ApiQuery({ name: 'search', required: false, description: 'Search by booking reference, email, or phone' })
  @ApiQuery({ name: 'status', required: false, description: 'Filter by booking status' })
  @ApiQuery({ name: 'returnLegStatus', required: false, description: 'Filter round-trip leg usage: NEITHER_USED | OUTBOUND_ONLY | INBOUND_ONLY | BOTH_USED | NOT_APPLICABLE' })
  @ApiQuery({ name: 'page', required: false, description: 'Page number' })
  @ApiQuery({ name: 'pageSize', required: false, description: 'Items per page' })
  findAll(
    @Query('search') search?: string,
    @Query('status') status?: string,
    @Query('returnLegStatus') returnLegStatus?: string,
    @Query('page') page?: string,
    @Query('pageSize') pageSize?: string,
  ) {
    return this.service.findAll({ 
      search, 
      status,
      returnLegStatus,
      page: page ? parseInt(page) : 1, 
      pageSize: pageSize ? parseInt(pageSize) : 20 
    });
  }
  
  @Post('guest')
  @ApiOperation({ 
    summary: 'Create guest booking — ONE_WAY | ROUND_TRIP | TRANSIT | ROUND_TRIP_TRANSIT (no login required)',
    description: `Creates a booking without requiring login. Supports all four booking types.

**bookingType: ONE_WAY (default)**
- scheduleId, holdId, originStationId, destinationStationId, seatClassId
- passengers[]: { seatId, passengerName, dateOfBirth, idDocumentType, … }

**bookingType: ROUND_TRIP**
- Above + returnScheduleId, returnHoldId, returnOriginStationId, returnDestinationStationId, returnSeatClassId
- passengers[]: each must include returnSeatId (seat on the return leg)

**bookingType: TRANSIT**
- scheduleId/holdId (leg-1) + leg2ScheduleId, leg2HoldId, transitStationId, leg2DestinationStationId
- passengers[]: each must include leg2SeatId

**bookingType: ROUND_TRIP_TRANSIT**
- All TRANSIT outbound fields + returnScheduleId/returnHoldId/returnOriginStationId/returnDestinationStationId/returnLeg2ScheduleId/returnLeg2HoldId/returnTransitStationId/returnLeg2DestinationStationId
- passengers[]: each must include leg2SeatId, returnSeatId, returnLeg2SeatId

**Optional account creation:** set createAccount=true with password — creates account from first passenger details, loyalty + wallet initialised.

**Verifayda:** Ethiopian nationals verified; international passengers require passportNumber + passportCountry.`
  })
  @ApiBody({
    type: CreateGuestBookingDto,
    examples: {
      ONE_WAY: {
        summary: 'ONE_WAY — single direct journey (guest)',
        value: {
          scheduleId: 'schedule-uuid',
          holdId: 'hold-uuid',
          originStationId: 'station-uuid',
          destinationStationId: 'station-uuid',
          seatClassId: 'seat-class-uuid',
          bookingType: 'ONE_WAY',
          displayCurrency: 'ETB',
          passengers: [{
            seatId: 'seat-uuid',
            passengerName: 'Abebe Kebede',
            dateOfBirth: '1990-05-15',
            idDocumentType: 'NATIONAL_ID',
            idDocumentNumber: 'ET123456789',
            nationality: 'Ethiopian',
            phone: '+251911234567',
            email: 'abebe@email.com',
          }],
          savePassengerDetails: true,
          deviceId: 'device-uuid-123',
        },
      },
      ROUND_TRIP: {
        summary: 'ROUND_TRIP — outbound + return, single PNR (guest)',
        value: {
          scheduleId: 'outbound-schedule-uuid',
          holdId: 'outbound-hold-uuid',
          originStationId: 'addis-station-uuid',
          destinationStationId: 'djibouti-station-uuid',
          seatClassId: 'seat-class-uuid',
          bookingType: 'ROUND_TRIP',
          returnScheduleId: 'return-schedule-uuid',
          returnHoldId: 'return-hold-uuid',
          returnOriginStationId: 'djibouti-station-uuid',
          returnDestinationStationId: 'addis-station-uuid',
          returnSeatClassId: 'seat-class-uuid',
          displayCurrency: 'ETB',
          passengers: [{
            seatId: 'outbound-seat-uuid',
            returnSeatId: 'return-seat-uuid',
            passengerName: 'Abebe Kebede',
            dateOfBirth: '1990-05-15',
            idDocumentType: 'NATIONAL_ID',
            idDocumentNumber: 'ET123456789',
            nationality: 'Ethiopian',
            phone: '+251911234567',
          }],
          savePassengerDetails: true,
          deviceId: 'device-uuid-123',
        },
      },
      TRANSIT: {
        summary: 'TRANSIT — connecting train, single PNR (guest)',
        value: {
          scheduleId: 'leg1-schedule-uuid',
          holdId: 'leg1-hold-uuid',
          originStationId: 'addis-station-uuid',
          destinationStationId: 'diredawa-station-uuid',
          seatClassId: 'seat-class-uuid',
          bookingType: 'TRANSIT',
          leg2ScheduleId: 'leg2-schedule-uuid',
          leg2HoldId: 'leg2-hold-uuid',
          transitStationId: 'diredawa-station-uuid',
          leg2DestinationStationId: 'djibouti-station-uuid',
          displayCurrency: 'ETB',
          passengers: [{
            seatId: 'leg1-seat-uuid',
            leg2SeatId: 'leg2-seat-uuid',
            passengerName: 'Abebe Kebede',
            dateOfBirth: '1990-05-15',
            idDocumentType: 'NATIONAL_ID',
            idDocumentNumber: 'ET123456789',
            nationality: 'Ethiopian',
            phone: '+251911234567',
          }],
          deviceId: 'device-uuid-123',
        },
      },
      ROUND_TRIP_TRANSIT: {
        summary: 'ROUND_TRIP_TRANSIT — round trip via connecting trains, 4 holds (guest)',
        value: {
          scheduleId: 'ob-leg1-schedule-uuid',
          holdId: 'ob-leg1-hold-uuid',
          originStationId: 'addis-station-uuid',
          destinationStationId: 'diredawa-station-uuid',
          seatClassId: 'seat-class-uuid',
          bookingType: 'ROUND_TRIP_TRANSIT',
          leg2ScheduleId: 'ob-leg2-schedule-uuid',
          leg2HoldId: 'ob-leg2-hold-uuid',
          transitStationId: 'diredawa-station-uuid',
          leg2DestinationStationId: 'djibouti-station-uuid',
          returnScheduleId: 'ret-leg1-schedule-uuid',
          returnHoldId: 'ret-leg1-hold-uuid',
          returnOriginStationId: 'djibouti-station-uuid',
          returnDestinationStationId: 'diredawa-station-uuid',
          returnLeg2ScheduleId: 'ret-leg2-schedule-uuid',
          returnLeg2HoldId: 'ret-leg2-hold-uuid',
          returnTransitStationId: 'diredawa-station-uuid',
          returnLeg2DestinationStationId: 'addis-station-uuid',
          displayCurrency: 'ETB',
          passengers: [{
            seatId: 'ob-leg1-seat-uuid',
            leg2SeatId: 'ob-leg2-seat-uuid',
            returnSeatId: 'ret-leg1-seat-uuid',
            returnLeg2SeatId: 'ret-leg2-seat-uuid',
            passengerName: 'Abebe Kebede',
            dateOfBirth: '1990-05-15',
            idDocumentType: 'NATIONAL_ID',
            idDocumentNumber: 'ET123456789',
            nationality: 'Ethiopian',
            phone: '+251911234567',
          }],
          deviceId: 'device-uuid-123',
        },
      },
    },
  })
  @ApiResponse({ status: 201, description: 'Booking created successfully with fareBreakdown' })
  @ApiResponse({ status: 400, description: 'Missing required seat IDs for bookingType, or Verifayda verification failed' })
  createGuest(@Body() dto: CreateGuestBookingDto) { 
    return this.guestService.createGuestBooking(dto); 
  }

  @Get('saved-passengers')
  @ApiOperation({ 
    summary: 'Get saved passenger profiles',
    description: 'Retrieve saved passenger details by userId (if logged in) or deviceId (for guest users)'
  })
  @ApiResponse({ status: 200, description: 'List of saved passenger profiles' })
  getSavedPassengers(@Query() query: GetSavedPassengersDto) {
    return this.guestService.getSavedPassengers(undefined, query.deviceId);
  }
  
  @Post()
  @UseGuards(JwtGuard)
  @ApiBearerAuth('JWT-auth')
  @ApiOperation({ 
    summary: 'Create booking — ONE_WAY | ROUND_TRIP | TRANSIT | ROUND_TRIP_TRANSIT',
    description: `Creates a booking for a logged-in passenger. bookingType controls which fields are required.

**ONE_WAY**
- scheduleId, holdId, originStationId, destinationStationId, seatClassId
- passengers[]: { seatId, passengerName, dateOfBirth, idDocumentType, … }

**ROUND_TRIP**
- Above + returnScheduleId, returnHoldId, returnOriginStationId, returnDestinationStationId, returnSeatClassId
- passengers[]: { seatId (outbound), returnSeatId (return), passengerName, … }
- Combined fare = outbound fare + return fare; single promo/loyalty deduction

**TRANSIT** (connecting train, single PNR)
- scheduleId/holdId for leg-1 + leg2ScheduleId, leg2HoldId, transitStationId, leg2DestinationStationId
- passengers[]: { seatId (leg-1), leg2SeatId (leg-2), passengerName, … }

**ROUND_TRIP_TRANSIT** (round trip, each direction via connecting train)
- All TRANSIT outbound fields + returnScheduleId, returnHoldId, returnOriginStationId, returnDestinationStationId, returnLeg2ScheduleId, returnLeg2HoldId, returnTransitStationId, returnLeg2DestinationStationId
- passengers[]: { seatId, leg2SeatId, returnSeatId, returnLeg2SeatId, passengerName, … }
- 4 holds required, 4 seat sets per passenger, single PNR, single payment

**Age-Based Pricing (all types)**
- ADULT (≥5 years): full fare per leg
- CHILD (<5 years): first child FREE per booking, subsequent children full fare`
  })
  @ApiBody({
    type: CreateBookingDto,
    examples: {
      ONE_WAY: {
        summary: 'ONE_WAY — single direct journey',
        value: {
          passengerId: 'passenger-uuid',
          scheduleId: 'schedule-uuid',
          holdId: 'hold-uuid',
          originStationId: 'station-uuid',
          destinationStationId: 'station-uuid',
          seatClassId: 'seat-class-uuid',
          bookingType: 'ONE_WAY',
          displayCurrency: 'ETB',
          passengers: [{
            seatId: 'seat-uuid',
            passengerName: 'Abebe Kebede',
            dateOfBirth: '1990-05-15',
            idDocumentType: 'NATIONAL_ID',
            idDocumentNumber: 'ET123456789',
            nationality: 'Ethiopian',
          }],
        },
      },
      ROUND_TRIP: {
        summary: 'ROUND_TRIP — outbound + return, single PNR',
        value: {
          passengerId: 'passenger-uuid',
          scheduleId: 'outbound-schedule-uuid',
          holdId: 'outbound-hold-uuid',
          originStationId: 'addis-station-uuid',
          destinationStationId: 'djibouti-station-uuid',
          seatClassId: 'seat-class-uuid',
          bookingType: 'ROUND_TRIP',
          returnScheduleId: 'return-schedule-uuid',
          returnHoldId: 'return-hold-uuid',
          returnOriginStationId: 'djibouti-station-uuid',
          returnDestinationStationId: 'addis-station-uuid',
          returnSeatClassId: 'seat-class-uuid',
          displayCurrency: 'ETB',
          passengers: [{
            seatId: 'outbound-seat-uuid',
            returnSeatId: 'return-seat-uuid',
            passengerName: 'Abebe Kebede',
            dateOfBirth: '1990-05-15',
            idDocumentType: 'NATIONAL_ID',
            idDocumentNumber: 'ET123456789',
            nationality: 'Ethiopian',
          }],
        },
      },
      TRANSIT: {
        summary: 'TRANSIT — connecting train, single PNR',
        value: {
          passengerId: 'passenger-uuid',
          scheduleId: 'leg1-schedule-uuid',
          holdId: 'leg1-hold-uuid',
          originStationId: 'addis-station-uuid',
          destinationStationId: 'diredawa-station-uuid',
          seatClassId: 'seat-class-uuid',
          bookingType: 'TRANSIT',
          leg2ScheduleId: 'leg2-schedule-uuid',
          leg2HoldId: 'leg2-hold-uuid',
          transitStationId: 'diredawa-station-uuid',
          leg2DestinationStationId: 'djibouti-station-uuid',
          displayCurrency: 'ETB',
          passengers: [{
            seatId: 'leg1-seat-uuid',
            leg2SeatId: 'leg2-seat-uuid',
            passengerName: 'Abebe Kebede',
            dateOfBirth: '1990-05-15',
            idDocumentType: 'NATIONAL_ID',
            idDocumentNumber: 'ET123456789',
            nationality: 'Ethiopian',
          }],
        },
      },
      ROUND_TRIP_TRANSIT: {
        summary: 'ROUND_TRIP_TRANSIT — round trip via connecting trains, 4 holds',
        value: {
          passengerId: 'passenger-uuid',
          scheduleId: 'ob-leg1-schedule-uuid',
          holdId: 'ob-leg1-hold-uuid',
          originStationId: 'addis-station-uuid',
          destinationStationId: 'diredawa-station-uuid',
          seatClassId: 'seat-class-uuid',
          bookingType: 'ROUND_TRIP_TRANSIT',
          leg2ScheduleId: 'ob-leg2-schedule-uuid',
          leg2HoldId: 'ob-leg2-hold-uuid',
          transitStationId: 'diredawa-station-uuid',
          leg2DestinationStationId: 'djibouti-station-uuid',
          returnScheduleId: 'ret-leg1-schedule-uuid',
          returnHoldId: 'ret-leg1-hold-uuid',
          returnOriginStationId: 'djibouti-station-uuid',
          returnDestinationStationId: 'diredawa-station-uuid',
          returnLeg2ScheduleId: 'ret-leg2-schedule-uuid',
          returnLeg2HoldId: 'ret-leg2-hold-uuid',
          returnTransitStationId: 'diredawa-station-uuid',
          returnLeg2DestinationStationId: 'addis-station-uuid',
          displayCurrency: 'ETB',
          passengers: [{
            seatId: 'ob-leg1-seat-uuid',
            leg2SeatId: 'ob-leg2-seat-uuid',
            returnSeatId: 'ret-leg1-seat-uuid',
            returnLeg2SeatId: 'ret-leg2-seat-uuid',
            passengerName: 'Abebe Kebede',
            dateOfBirth: '1990-05-15',
            idDocumentType: 'NATIONAL_ID',
            idDocumentNumber: 'ET123456789',
            nationality: 'Ethiopian',
          }],
        },
      },
    },
  })
  @ApiResponse({ status: 201, description: 'Booking created with fare breakdown' })
  @ApiResponse({ status: 400, description: 'Missing required fields for bookingType, or Verifayda verification failed' })
  @ApiResponse({ status: 404, description: 'Schedule or seat hold not found' })
  create(@Body() dto: CreateBookingDto) { 
    return this.service.create(dto); 
  }
  
  @Get(':id/usage')
  @ApiOperation({ 
    summary: 'Check if booking is in use',
    description: 'Returns list of modules/data that reference this booking'
  })
  @ApiResponse({ status: 200, description: 'Usage information retrieved' })
  @ApiResponse({ status: 404, description: 'Booking not found' })
  checkUsage(@Param('id') id: string) {
    return this.service.checkBookingUsage(id);
  }

  @Get(':bookingRef')
  @ApiOperation({ 
    summary: 'Get booking details by reference (no auth required)',
    description: 'Returns booking with passenger categories, Verifayda verification status, and multi-currency amounts. Works for both guest and authenticated bookings.'
  })
  @ApiResponse({ status: 200, description: 'Booking details with adult/child counts and currency conversion' })
  @ApiResponse({ status: 404, description: 'Booking not found' })
  getByRef(@Param('bookingRef') ref: string) { 
    return this.service.getByRef(ref); 
  }
  
  @Patch(':bookingRef/modify')
  @UseGuards(JwtGuard)
  @ApiBearerAuth('JWT-auth')
  @ApiOperation({ 
    summary: 'Modify booking seats or trip',
    description: 'Allows modification of confirmed bookings before departure'
  })
  @ApiResponse({ status: 200, description: 'Booking modified successfully' })
  @ApiResponse({ status: 400, description: 'Cannot modify cancelled or past bookings' })
  modify(@Body() dto: ModifyBookingDto) {
    return this.service.modify(dto);
  }
  
  @Delete(':id')
  @ApiOperation({ 
    summary: 'Delete booking (admin only)',
    description: 'Permanently deletes a booking record'
  })
  @ApiResponse({ status: 200, description: 'Booking deleted successfully' })
  @ApiResponse({ status: 404, description: 'Booking not found' })
  delete(@Param('id') id: string) { 
    return this.service.delete(id); 
  }

  @Patch(':id')
  @ApiOperation({ 
    summary: 'Update booking details',
    description: 'Updates booking information for admin/agent operations'
  })
  @ApiResponse({ status: 200, description: 'Booking updated successfully' })
  @ApiResponse({ status: 404, description: 'Booking not found' })
  update(@Param('id') id: string, @Body() dto: any) { 
    return this.service.update(id, dto); 
  }

  @Delete(':bookingRef')
  @UseGuards(JwtGuard)
  @ApiBearerAuth('JWT-auth')
  @ApiOperation({ 
    summary: 'Cancel booking with refund',
    description: 'Cancels booking and processes refund (80% for confirmed bookings)'
  })
  @ApiResponse({ status: 200, description: 'Booking cancelled with refund amount' })
  @ApiResponse({ status: 400, description: 'Booking already cancelled' })
  cancel(@Param('bookingRef') ref: string, @Body() dto: CancelBookingDto) { 
    return this.service.cancel(ref, dto.reason); 
  }
}
