import { Controller, Get, Post, Body, Patch, Param, Delete, UseGuards, Query, Req, Logger, HttpException, HttpStatus } from '@nestjs/common';
import { ApiTags, ApiOperation, ApiResponse, ApiParam, ApiBearerAuth, ApiQuery, ApiBody } from '@nestjs/swagger';
import { AppointmentService } from './appointment.service';
import { CreateAppointmentDto } from './dto/create-appointment.dto';
import { JwtAuthGuard } from 'common/guards/jwt-auth.guard';
import { RolesGuard } from 'common/guards/roles.guard';
import { UserRole } from 'common/enum/UserRole.enum';
import { Roles } from 'common/decorators/role.decorator';
import { UpdateAppointmentDto } from './dto/update-appointment.dto';
import { AppointmentResponseDto } from './dto/appointment-response.dto';
import { UserEntity } from 'modules/user/entity/users.entity';
import { PermissionsGuard } from 'common/guards/ppermissions.guard';

@ApiTags('Appointments')
@ApiBearerAuth()
@Controller({ path: 'appointments', version: '1' })
@UseGuards(JwtAuthGuard, RolesGuard, PermissionsGuard)
export class AppointmentController {
  private readonly logger = new Logger(AppointmentController.name);
  constructor(private readonly appointmentService: AppointmentService) {}

  @Get('available-slots')
  @Roles(UserRole.USER, UserRole.ADMIN, UserRole.SUPER_ADMIN, UserRole.CLIENT)
  @ApiOperation({ summary: 'Get available time slots for a given date' })
  @ApiQuery({ name: 'date', required: true, description: 'Date in YYYY-MM-DD format' })
  @ApiResponse({ status: 200, description: 'Available time slots retrieved' })
  @ApiResponse({ status: 400, description: 'Invalid date format' })
  async getAvailableSlots(@Query('date') date: string) {
    this.logger.log('Getting available slots for date', date);
    const availableTimeSlots = await this.appointmentService.getAvailableTimeSlots(new Date(date));
    return {
      date: date,
      availableTimeSlots,
    };
  }

  @Post()
  @Roles(UserRole.USER, UserRole.ADMIN, UserRole.SUPER_ADMIN, UserRole.CLIENT)
  @ApiOperation({ summary: 'Create a new appointment' })
  @ApiResponse({ status: 201, description: 'Appointment successfully created', type: AppointmentResponseDto })
  @ApiResponse({ status: 400, description: 'Invalid input' })
  create(@Body() createAppointmentDto: CreateAppointmentDto, @Req() req) {
    const { user } = req as { user: UserEntity };
    this.logger.log('Creating appointment', user);

    createAppointmentDto['userId'] = user.id;
    createAppointmentDto.fullName = user.firstName + ' ' + user.lastName;

    return this.appointmentService.create(createAppointmentDto);
  }

  @Get()
  @Roles(UserRole.SUPER_ADMIN, UserRole.ADMIN)
  @ApiOperation({ summary: 'Retrieve all appointments' })
  @ApiResponse({ status: 200, description: 'List of appointments retrieved', type: AppointmentResponseDto, isArray: true })
  @ApiResponse({ status: 404, description: 'No appointments found' })
  async findAll() {
    return this.appointmentService.findAll();
  }

  @Get('my-appointments')
  @Roles(UserRole.USER, UserRole.ADMIN, UserRole.SUPER_ADMIN, UserRole.CLIENT)
  @ApiOperation({ summary: 'Retrieve user appointments' })
  @ApiQuery({ name: 'userId', required: false, description: 'Filter by user ID' })
  @ApiResponse({ status: 200, description: 'List of appointments retrieved', type: AppointmentResponseDto, isArray: true })
  @ApiResponse({ status: 404, description: 'No appointments found' })
  findByUserId(@Req() req: any) {
    const { user } = req;
    return this.appointmentService.findByUserId(user.id);
  }

  @Get(':id')
  @Roles(UserRole.USER, UserRole.ADMIN, UserRole.SUPER_ADMIN, UserRole.CLIENT)
  @ApiOperation({ summary: 'Retrieve a specific appointment' })
  @ApiParam({ name: 'id', type: 'number', description: 'Appointment ID' })
  @ApiResponse({ status: 200, description: 'Appointment found', type: AppointmentResponseDto })
  @ApiResponse({ status: 404, description: 'Appointment not found' })
  findOne(@Param('id') id: number, @Req() req: any) {
    const { user } = req;
    this.logger.log('Finding appointment', user);

    return this.appointmentService.findOne(id, user.id, user.role);
  }

  @Patch(':id')
  @Roles(UserRole.USER, UserRole.ADMIN, UserRole.SUPER_ADMIN)
  @ApiOperation({ summary: 'Update an existing appointment' })
  @ApiBody({ type: UpdateAppointmentDto })
  @ApiParam({ name: 'id', type: 'number', description: 'Appointment ID' })
  @ApiResponse({ status: 200, description: 'Appointment successfully updated', type: AppointmentResponseDto })
  @ApiResponse({ status: 404, description: 'Appointment not found' })
  async update(@Param('id') id: number, @Body() updateAppointmentDto: UpdateAppointmentDto, @Req() req: any) {
    const { user } = req;
    if (!user) {
      throw new HttpException('Unauthorized', HttpStatus.UNAUTHORIZED);
    }
    return this.appointmentService.update(id, user.id, user.role, updateAppointmentDto);
  }

  @Delete(':id')
  @Roles(UserRole.USER, UserRole.ADMIN, UserRole.SUPER_ADMIN, UserRole.CLIENT)
  @ApiOperation({ summary: 'Delete an appointment' })
  @ApiParam({ name: 'id', type: 'number', description: 'Appointment ID' })
  @ApiResponse({ status: 200, description: 'Appointment successfully deleted' })
  @ApiResponse({ status: 404, description: 'Appointment not found' })
  async remove(@Param('id') id: number, @Req() req: any) {
    const { user } = req;
    if (!user) {
      throw new HttpException('Unauthorized', HttpStatus.UNAUTHORIZED);
    }
    return this.appointmentService.remove(id, user.id, user.role);
  }
}
