import { Body, Controller, Delete, Get, Param, Patch, Post, Query, ParseIntPipe, UseGuards } from '@nestjs/common';
import { ApiTags, ApiOperation, ApiBearerAuth, ApiParam, ApiQuery, ApiResponse } from '@nestjs/swagger';
import { SchedulesService } from './schedules.service';
import { CreateScheduleDto, UpdateScheduleDto, CreateFareRuleDto, UpdateScheduleStatusDto, UpdateStopTimeDto, ListSchedulesDto, BulkCreateSchedulesDto, BulkSchedulesResponseDto } from './schedules.dto';
import { JwtGuard } from '../../common/jwt.guard';
import { TripStatus } from '@prisma/client';

@ApiTags('Schedule')
@Controller('schedules')
export class SchedulesController {
  constructor(private service: SchedulesService) {}

  @Post('bulk-generate')
  @UseGuards(JwtGuard) @ApiBearerAuth('JWT-auth')
  @ApiOperation({ summary: 'Bulk generate repetitive schedules' })
  bulkGenerateSchedules(@Body() dto: BulkCreateSchedulesDto) {
    return this.service.bulkGenerateSchedules(dto);
  }

  @Post()
  @UseGuards(JwtGuard) @ApiBearerAuth('JWT-auth')
  @ApiOperation({ summary: 'Create a train schedule from a route template' })
  createSchedule(@Body() dto: CreateScheduleDto) { return this.service.createSchedule(dto); }

  @Get()
  @ApiOperation({ summary: 'List schedules with optional filters' })
  @ApiQuery({ name: 'date', required: false })
  @ApiQuery({ name: 'routeId', required: false })
  @ApiQuery({ name: 'trainId', required: false })
  @ApiQuery({ name: 'status', required: false, enum: TripStatus })
  listSchedules(
    @Query('date') date?: string,
    @Query('routeId') routeId?: string,
    @Query('trainId') trainId?: string,
    @Query('status') status?: TripStatus,
  ) {
    return this.service.listSchedules({ date, routeId, trainId, status });
  }

  // ===== SPECIFIC ROUTES (must come BEFORE generic :id routes) =====

  @Post('fares')
  @UseGuards(JwtGuard) @ApiBearerAuth('JWT-auth')
  @ApiOperation({ summary: 'Create a fare rule scoped to a schedule or route code' })
  @ApiResponse({ status: 201, description: 'Fare rule created' })
  createFareRule(@Body() dto: CreateFareRuleDto) { return this.service.createFareRule(dto); }

  @Patch('fares/:id')
  @UseGuards(JwtGuard) @ApiBearerAuth('JWT-auth')
  @ApiOperation({ summary: 'Update a fare rule' })
  @ApiParam({ name: 'id', description: 'FareRule UUID' })
  @ApiResponse({ status: 200, description: 'Fare rule updated' })
  updateFareRule(@Param('id') id: string, @Body() dto: Partial<CreateFareRuleDto>) {
    return this.service.updateFareRule(id, dto);
  }

  @Delete('fares/:id')
  @UseGuards(JwtGuard) @ApiBearerAuth('JWT-auth')
  @ApiOperation({ summary: 'Delete a fare rule' })
  @ApiParam({ name: 'id', description: 'FareRule UUID' })
  @ApiResponse({ status: 200, description: 'Fare rule deleted' })
  deleteFareRule(@Param('id') id: string) { return this.service.deleteFareRule(id); }

  @Post('segment-fares')
  @UseGuards(JwtGuard) @ApiBearerAuth('JWT-auth')
  @ApiOperation({ summary: 'Create a segment fare rule' })
  createSegmentFareRule(@Body() dto: any) { return this.service.createSegmentFareRule(dto); }

  @Get('routes/:routeId/segment-fares')
  @ApiOperation({ summary: 'List all segment fare rules for a route' })
  @ApiParam({ name: 'routeId', description: 'Route UUID' })
  getSegmentFares(@Param('routeId') routeId: string) { return this.service.getSegmentFares(routeId); }

  @Patch('segment-fares/:id')
  @UseGuards(JwtGuard) @ApiBearerAuth('JWT-auth')
  @ApiOperation({ summary: 'Update a segment fare rule' })
  @ApiParam({ name: 'id', description: 'SegmentFareRule UUID' })
  updateSegmentFareRule(@Param('id') id: string, @Body() dto: any) { return this.service.updateSegmentFareRule(id, dto); }

  @Delete('segment-fares/:id')
  @UseGuards(JwtGuard) @ApiBearerAuth('JWT-auth')
  @ApiOperation({ summary: 'Delete a segment fare rule' })
  @ApiParam({ name: 'id', description: 'SegmentFareRule UUID' })
  deleteSegmentFareRule(@Param('id') id: string) { return this.service.deleteSegmentFareRule(id); }

  // ===== PARAMETRIZED ROUTES (generic :id routes come AFTER specific routes) =====

  @Get(':id')
  @ApiOperation({ summary: 'Get schedule detail' })
  @ApiParam({ name: 'id', description: 'TrainSchedule UUID' })
  getSchedule(@Param('id') id: string) { return this.service.getSchedule(id); }

  @Patch(':id')
  @UseGuards(JwtGuard) @ApiBearerAuth('JWT-auth')
  @ApiOperation({ summary: 'Update a schedule (partial)' })
  @ApiParam({ name: 'id', description: 'TrainSchedule UUID' })
  updateSchedule(@Param('id') id: string, @Body() dto: UpdateScheduleDto) {
    return this.service.updateSchedulePartial(id, dto);
  }

  @Patch(':id/status')
  @UseGuards(JwtGuard) @ApiBearerAuth('JWT-auth')
  @ApiOperation({ summary: 'Update schedule status' })
  @ApiParam({ name: 'id', description: 'TrainSchedule UUID' })
  updateStatus(@Param('id') id: string, @Body() dto: UpdateScheduleStatusDto) {
    return this.service.updateScheduleStatus(id, dto);
  }

  @Delete(':id')
  @UseGuards(JwtGuard) @ApiBearerAuth('JWT-auth')
  @ApiOperation({ summary: 'Delete a schedule' })
  @ApiParam({ name: 'id', description: 'TrainSchedule UUID' })
  deleteSchedule(@Param('id') id: string) { return this.service.deleteSchedule(id); }

  @Get(':id/stops')
  @ApiOperation({ summary: 'List all stops for a schedule' })
  @ApiParam({ name: 'id', description: 'TrainSchedule UUID' })
  getStops(@Param('id') id: string) { return this.service.getStops(id); }

  @Patch(':id/stops/:sequence')
  @UseGuards(JwtGuard) @ApiBearerAuth('JWT-auth')
  @ApiOperation({ summary: 'Update a stop time' })
  @ApiParam({ name: 'id', description: 'TrainSchedule UUID' })
  @ApiParam({ name: 'sequence', description: 'Stop sequence number' })
  updateStop(
    @Param('id') id: string,
    @Param('sequence', ParseIntPipe) sequence: number,
    @Body() dto: UpdateStopTimeDto,
  ) { return this.service.updateStop(id, sequence, dto); }

  @Get(':scheduleId/fares/stored')
  @ApiOperation({ summary: 'Get stored fare rules for a schedule' })
  @ApiParam({ name: 'scheduleId', description: 'TrainSchedule UUID' })
  getStoredFares(@Param('scheduleId') scheduleId: string) {
    return this.service.getFareRules(scheduleId);
  }

  @Get(':scheduleId/fares/all')
  @ApiOperation({ summary: 'Get fares for all active seat classes from the fare engine' })
  @ApiParam({ name: 'scheduleId', description: 'TrainSchedule UUID' })
  @ApiQuery({ name: 'nationality', required: false })
  getAllFares(
    @Param('scheduleId') scheduleId: string,
    @Query('nationality') nationality?: string,
  ) {
    return this.service.getAllFaresFromEngine(scheduleId, nationality);
  }

  @Get(':scheduleId/fares')
  @ApiOperation({ summary: 'Get fare for a specific seat class from the fare engine' })
  @ApiParam({ name: 'scheduleId', description: 'TrainSchedule UUID' })
  @ApiQuery({ name: 'seatClassId', required: true })
  @ApiQuery({ name: 'nationality', required: false })
  getFare(
    @Param('scheduleId') scheduleId: string,
    @Query('seatClassId') seatClassId: string,
    @Query('nationality') nationality?: string,
  ) {
    return this.service.getFareFromEngine(scheduleId, seatClassId, nationality);
  }

  @Post(':id/fares/sync')
  @ApiOperation({ summary: 'Sync fares from fare engine' })
  @ApiParam({ name: 'id', description: 'TrainSchedule UUID' })
  syncFares(@Param('id') id: string) { return this.service.syncFaresFromEngine(id); }

  @Post(':id/coaches')
  @UseGuards(JwtGuard) @ApiBearerAuth('JWT-auth')
  @ApiOperation({ summary: 'Assign coaches to a schedule' })
  @ApiParam({ name: 'id', description: 'TrainSchedule UUID' })
  assignCoaches(
    @Param('id') id: string,
    @Body() dto: { coaches: Array<{ coachId: string; positionNumber: number }> },
  ) {
    return this.service.assignCoaches(id, dto.coaches);
  }

  @Get(':id/coaches')
  @ApiOperation({ summary: 'Get assigned coaches for a schedule' })
  @ApiParam({ name: 'id', description: 'TrainSchedule UUID' })
  getAssignedCoaches(@Param('id') id: string) { return this.service.getAssignedCoaches(id); }

  @Delete(':id/coaches/:coachId')
  @UseGuards(JwtGuard) @ApiBearerAuth('JWT-auth')
  @ApiOperation({ summary: 'Remove a coach assignment' })
  @ApiParam({ name: 'id', description: 'TrainSchedule UUID' })
  @ApiParam({ name: 'coachId', description: 'Coach UUID' })
  removeCoachAssignment(@Param('id') id: string, @Param('coachId') coachId: string) {
    return this.service.removeCoachAssignment(id, coachId);
  }
}
