import {
  Body,
  Controller,
  Delete,
  Get,
  HttpCode,
  HttpStatus,
  Param,
  ParseUUIDPipe,
  Patch,
  Post,
  Put,
  Query,
} from '@nestjs/common';
import { ApiBearerAuth, ApiOperation, ApiTags } from '@nestjs/swagger';

import { FleetManage, FleetView } from '../../common/booking-guards';
import { FREIGHT_PERMS } from '../../seed/freight-permissions.registry';
import { AssignTrainWagonsDto } from './dto/assign-train-wagons.dto';
import { BuildTrainDto } from './dto/build-train.dto';
import { ListBuiltTrainsQueryDto } from './dto/list-built-trains-query.dto';
import { ReorderTrainWagonsDto } from './dto/reorder-train-wagons.dto';
import { UpdateTrainDetailsDto } from './dto/update-train-details.dto';
import { UpdateTrainLocomotivesDto } from './dto/update-train-locomotives.dto';
import { UpdateTrainYardDto } from './dto/update-train-yard.dto';
import { TrainBuilderService } from './train-builder.service';

@ApiTags('train-builder')
@ApiBearerAuth()
@Controller('train-builder')
@FleetView(FREIGHT_PERMS.trains.view)
export class TrainBuilderController {
  constructor(private readonly trainBuilderService: TrainBuilderService) {}

  @Post()
  @FleetManage(FREIGHT_PERMS.trains.create)
  @ApiOperation({ summary: 'Build a train: code + yard + 2+ locomotives (+ optional wagons)' })
  build(@Body() dto: BuildTrainDto) {
    return this.trainBuilderService.buildTrain(dto);
  }

  @Get()
  @ApiOperation({ summary: 'Paginated built trains with composition summary' })
  list(@Query() query: ListBuiltTrainsQueryDto) {
    return this.trainBuilderService.listBuilt(query);
  }

  // Must be declared before @Get(':id') so the path isn't captured as an id.
  @Get('used-train-numbers')
  @ApiOperation({
    summary: 'Import/export run numbers already claimed by existing trains',
  })
  usedTrainNumbers() {
    return this.trainBuilderService.usedTrainNumbers();
  }

  @Get(':id')
  @ApiOperation({ summary: 'Full train composition: locomotives, ordered wagons, totals vs. limits' })
  composition(@Param('id', ParseUUIDPipe) id: string) {
    return this.trainBuilderService.getComposition(id);
  }

  @Put(':id/locomotives')
  @FleetManage(FREIGHT_PERMS.trains.update)
  @ApiOperation({ summary: 'Replace the locomotive set (minimum 2, same yard)' })
  setLocomotives(
    @Param('id', ParseUUIDPipe) id: string,
    @Body() dto: UpdateTrainLocomotivesDto,
  ) {
    return this.trainBuilderService.setLocomotives(id, dto);
  }

  @Patch(':id/details')
  @FleetManage(FREIGHT_PERMS.trains.update)
  @ApiOperation({
    summary: "Edit the train's name and fixed import/export run numbers",
  })
  updateDetails(
    @Param('id', ParseUUIDPipe) id: string,
    @Body() dto: UpdateTrainDetailsDto,
  ) {
    return this.trainBuilderService.updateDetails(id, dto);
  }

  @Patch(':id/yard')
  @FleetManage(FREIGHT_PERMS.trains.update)
  @ApiOperation({
    summary: 'Relocate the train — its locomotives and wagons move to the new yard with it',
  })
  setYard(@Param('id', ParseUUIDPipe) id: string, @Body() dto: UpdateTrainYardDto) {
    return this.trainBuilderService.setYard(id, dto.currentYardId);
  }

  @Post(':id/wagons')
  @FleetManage(FREIGHT_PERMS.trains.assignWagons)
  @ApiOperation({ summary: "Append AVAILABLE wagons from the train's yard to the consist" })
  assignWagons(@Param('id', ParseUUIDPipe) id: string, @Body() dto: AssignTrainWagonsDto) {
    return this.trainBuilderService.assignWagons(id, dto);
  }

  @Delete(':id/wagons/:wagonId')
  @FleetManage(FREIGHT_PERMS.trains.assignWagons)
  @ApiOperation({ summary: 'Detach one wagon from the consist' })
  removeWagon(
    @Param('id', ParseUUIDPipe) id: string,
    @Param('wagonId', ParseUUIDPipe) wagonId: string,
  ) {
    return this.trainBuilderService.removeWagon(id, wagonId);
  }

  @Post(':id/wagons/:wagonId/maintenance')
  @FleetManage(FREIGHT_PERMS.trains.assignWagons)
  @ApiOperation({ summary: 'Detach one wagon and move it to MAINTENANCE status' })
  sendWagonToMaintenance(
    @Param('id', ParseUUIDPipe) id: string,
    @Param('wagonId', ParseUUIDPipe) wagonId: string,
  ) {
    return this.trainBuilderService.sendWagonToMaintenance(id, wagonId);
  }

  @Post(':id/reorder-wagons')
  @FleetManage(FREIGHT_PERMS.trains.assignWagons)
  @ApiOperation({ summary: 'Persist a drag-reorder of the full consist' })
  reorderWagons(@Param('id', ParseUUIDPipe) id: string, @Body() dto: ReorderTrainWagonsDto) {
    return this.trainBuilderService.reorderWagons(id, dto);
  }

  @Post(':id/deactivate')
  @FleetManage(FREIGHT_PERMS.trains.update)
  @ApiOperation({
    summary: 'Deactivate the train (park it) — only allowed with no active schedule',
  })
  deactivate(@Param('id', ParseUUIDPipe) id: string) {
    return this.trainBuilderService.deactivate(id);
  }

  @Post(':id/activate')
  @FleetManage(FREIGHT_PERMS.trains.update)
  @ApiOperation({ summary: 'Reactivate a deactivated train back to AVAILABLE' })
  activate(@Param('id', ParseUUIDPipe) id: string) {
    return this.trainBuilderService.activate(id);
  }

  @Delete(':id')
  @FleetManage(FREIGHT_PERMS.trains.delete)
  @HttpCode(HttpStatus.NO_CONTENT)
  @ApiOperation({ summary: 'Disband the train (release wagons and locomotives)' })
  disband(@Param('id', ParseUUIDPipe) id: string) {
    return this.trainBuilderService.disband(id);
  }
}
