import {
  Controller,
  Get,
  Post,
  Patch,
  Body,
  Param,
  Query,
  UseGuards,
  ParseUUIDPipe,
} from '@nestjs/common';
import {
  ApiTags,
  ApiOperation,
  ApiBearerAuth,
  ApiResponse,
  ApiParam,
} from '@nestjs/swagger';
import { ScheduleService } from './schedule.service';
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
import { RolesGuard } from '../auth/guards/roles.guard';
import { Roles, UserRole } from '../../common/decorators/roles.decorator';
import {
  CurrentUser,
  JwtPayload,
} from '../../common/decorators/current-user.decorator';
import {
  CreateTrainingDto,
  UpdateTrainingDto,
  RescheduleTrainingDto,
  CancelTrainingDto,
  FindTrainingsDto,
} from './dto';

@ApiTags('Trainings')
@ApiBearerAuth()
@Controller('trainings')
@UseGuards(JwtAuthGuard)
export class ScheduleController {
  constructor(private readonly scheduleService: ScheduleService) {}

  @Get()
  @ApiOperation({
    summary: 'List trainings with pagination and filters',
  })
  @ApiResponse({ status: 200, description: 'Paginated list of trainings' })
  async findAll(
    @CurrentUser() user: JwtPayload,
    @Query() query: FindTrainingsDto,
  ) {
    const params = this.applyTrainerFilter(user, query);
    return this.scheduleService.findAll(user.clubId, params);
  }

  @Get('date/:date')
  @ApiOperation({
    summary: 'Get all trainings for a specific date (YYYY-MM-DD)',
  })
  @ApiParam({ name: 'date', description: 'Date in YYYY-MM-DD format' })
  @ApiResponse({ status: 200, description: 'List of trainings for the date' })
  async getByDate(
    @CurrentUser() user: JwtPayload,
    @Param('date') date: string,
  ) {
    const trainerId =
      user.role === UserRole.TRAINER ? user.sub : undefined;

    return this.scheduleService.getByDate(user.clubId, date, trainerId);
  }

  @Get('slots/:trainerId/:date')
  @UseGuards(RolesGuard)
  @Roles(
    UserRole.TRAINER,
    UserRole.COORDINATOR,
    UserRole.MANAGER,
    UserRole.RECEPTIONIST,
    UserRole.CLUB_ADMIN,
  )
  @ApiOperation({
    summary: 'Get available time slots for a trainer on a given date',
  })
  @ApiParam({ name: 'trainerId', description: 'Trainer UUID' })
  @ApiParam({ name: 'date', description: 'Date in YYYY-MM-DD format' })
  @ApiResponse({ status: 200, description: 'List of available time slots' })
  async getTrainerSlots(
    @CurrentUser() user: JwtPayload,
    @Param('trainerId', ParseUUIDPipe) trainerId: string,
    @Param('date') date: string,
  ) {
    return this.scheduleService.getTrainerSlots(
      user.clubId,
      trainerId,
      date,
    );
  }

  @Get(':id')
  @ApiOperation({ summary: 'Get training by ID with all relations' })
  @ApiParam({ name: 'id', description: 'Training UUID' })
  @ApiResponse({ status: 200, description: 'Training details' })
  @ApiResponse({ status: 404, description: 'Training not found' })
  async findById(
    @CurrentUser() user: JwtPayload,
    @Param('id', ParseUUIDPipe) id: string,
  ) {
    return this.scheduleService.findById(user.clubId, id);
  }

  @Post()
  @UseGuards(RolesGuard)
  @Roles(
    UserRole.TRAINER,
    UserRole.COORDINATOR,
    UserRole.MANAGER,
    UserRole.RECEPTIONIST,
    UserRole.CLUB_ADMIN,
  )
  @ApiOperation({ summary: 'Create a new training' })
  @ApiResponse({ status: 201, description: 'Training created' })
  @ApiResponse({ status: 403, description: 'Insufficient role' })
  async create(
    @CurrentUser() user: JwtPayload,
    @Body() dto: CreateTrainingDto,
  ) {
    // For TRAINER role, always use own ID; for other roles, use dto.trainerId or fallback to own ID
    const trainerId =
      user.role === UserRole.TRAINER
        ? user.sub
        : (dto.trainerId ?? user.sub);

    return this.scheduleService.create(user.clubId, trainerId, dto);
  }

  @Patch(':id')
  @UseGuards(RolesGuard)
  @Roles(
    UserRole.TRAINER,
    UserRole.COORDINATOR,
    UserRole.MANAGER,
    UserRole.CLUB_ADMIN,
  )
  @ApiOperation({ summary: 'Update an existing training (PLANNED only)' })
  @ApiParam({ name: 'id', description: 'Training UUID' })
  @ApiResponse({ status: 200, description: 'Training updated' })
  @ApiResponse({ status: 400, description: 'Training is not in PLANNED status' })
  @ApiResponse({ status: 404, description: 'Training not found' })
  async update(
    @CurrentUser() user: JwtPayload,
    @Param('id', ParseUUIDPipe) id: string,
    @Body() dto: UpdateTrainingDto,
  ) {
    return this.scheduleService.update(user.clubId, id, dto);
  }

  @Post(':id/cancel')
  @UseGuards(RolesGuard)
  @Roles(
    UserRole.TRAINER,
    UserRole.COORDINATOR,
    UserRole.MANAGER,
    UserRole.CLUB_ADMIN,
  )
  @ApiOperation({ summary: 'Cancel a training with a reason' })
  @ApiParam({ name: 'id', description: 'Training UUID' })
  @ApiResponse({ status: 200, description: 'Training cancelled' })
  @ApiResponse({ status: 400, description: 'Training cannot be cancelled' })
  @ApiResponse({ status: 404, description: 'Training not found' })
  async cancel(
    @CurrentUser() user: JwtPayload,
    @Param('id', ParseUUIDPipe) id: string,
    @Body() dto: CancelTrainingDto,
  ) {
    return this.scheduleService.cancel(user.clubId, id, dto);
  }

  @Post(':id/reschedule')
  @UseGuards(RolesGuard)
  @Roles(
    UserRole.TRAINER,
    UserRole.COORDINATOR,
    UserRole.MANAGER,
    UserRole.CLUB_ADMIN,
  )
  @ApiOperation({
    summary: 'Reschedule a training to a new date/time',
  })
  @ApiParam({ name: 'id', description: 'Training UUID' })
  @ApiResponse({ status: 200, description: 'Training rescheduled' })
  @ApiResponse({ status: 400, description: 'Training cannot be rescheduled' })
  @ApiResponse({ status: 404, description: 'Training not found' })
  async reschedule(
    @CurrentUser() user: JwtPayload,
    @Param('id', ParseUUIDPipe) id: string,
    @Body() dto: RescheduleTrainingDto,
  ) {
    return this.scheduleService.reschedule(user.clubId, id, dto);
  }

  @Post(':id/complete')
  @UseGuards(RolesGuard)
  @Roles(
    UserRole.TRAINER,
    UserRole.COORDINATOR,
    UserRole.MANAGER,
    UserRole.CLUB_ADMIN,
  )
  @ApiOperation({
    summary: 'Mark training as completed and update client activity',
  })
  @ApiParam({ name: 'id', description: 'Training UUID' })
  @ApiResponse({ status: 200, description: 'Training completed' })
  @ApiResponse({ status: 400, description: 'Training cannot be completed' })
  @ApiResponse({ status: 404, description: 'Training not found' })
  async complete(
    @CurrentUser() user: JwtPayload,
    @Param('id', ParseUUIDPipe) id: string,
  ) {
    return this.scheduleService.complete(user.clubId, id);
  }

  @Post(':id/confirm')
  @UseGuards(RolesGuard)
  @Roles(
    UserRole.TRAINER,
    UserRole.COORDINATOR,
    UserRole.MANAGER,
    UserRole.CLUB_ADMIN,
  )
  @ApiOperation({ summary: 'Confirm a planned training' })
  @ApiParam({ name: 'id', description: 'Training UUID' })
  @ApiResponse({ status: 200, description: 'Training confirmed' })
  @ApiResponse({ status: 400, description: 'Training is not in PLANNED status' })
  @ApiResponse({ status: 404, description: 'Training not found' })
  async confirm(
    @CurrentUser() user: JwtPayload,
    @Param('id', ParseUUIDPipe) id: string,
  ) {
    return this.scheduleService.confirm(user.clubId, id);
  }

  /**
   * For TRAINER role, force the trainerId filter to their own user ID.
   * COORDINATOR and MANAGER see all trainings or use the provided filter.
   */
  private applyTrainerFilter(
    user: JwtPayload,
    query: FindTrainingsDto,
  ): FindTrainingsDto {
    if (user.role === UserRole.TRAINER) {
      return { ...query, trainerId: user.sub };
    }
    return query;
  }
}
