import {
  Controller,
  Get,
  Post,
  Body,
  Put,
  Param,
  Delete,
  Query,
  HttpCode,
  HttpStatus,
} from '@nestjs/common';
import {
  ApiTags,
  ApiOperation,
  ApiResponse,
  ApiBearerAuth,
  ApiParam,
} from '@nestjs/swagger';
import { AbsencesService } from './absences.service';
import { CreateAbsenceDto } from './dto/create-absence.dto';
import { UpdateAbsenceDto } from './dto/update-absence.dto';
import {
  QueryAbsencesDto,
  QueryCalendarDto,
  QueryConflictsDto,
} from './dto/query-absences.dto';
import { ApproveAbsenceDto, RejectAbsenceDto } from './dto/approve-absence.dto';
import { RequirePermissions } from '../../../auth/permissions/permissions.decorator';
import { Permission } from '../../../auth/permissions/permissions.enum';
import { CurrentUser } from '../../../auth/decorators/current-user.decorator';
import { JwtPayload } from '../../../auth/interfaces/jwt-payload.interface';
import { AuditLog } from '../../audit/audit.interceptor';

@ApiTags('hr/absences')
@ApiBearerAuth('JWT-auth')
@Controller('hr/absences')
export class AbsencesController {
  constructor(private readonly absencesService: AbsencesService) {}

  @Post()
  @RequirePermissions(Permission.ABSENCES_CREATE)
  @AuditLog('Absence', 'CREATE')
  @ApiOperation({ summary: 'Create a new absence request' })
  @ApiResponse({
    status: 201,
    description: 'Absence request created successfully',
  })
  @ApiResponse({ status: 400, description: 'Bad request - validation error or conflict' })
  @ApiResponse({ status: 401, description: 'Unauthorized' })
  @ApiResponse({ status: 403, description: 'Forbidden' })
  create(
    @Body() createDto: CreateAbsenceDto,
    @CurrentUser() currentUser: JwtPayload,
  ) {
    return this.absencesService.create(createDto, currentUser);
  }

  @Get()
  @RequirePermissions(Permission.ABSENCES_VIEW)
  @ApiOperation({ summary: 'Get all absences with pagination and filtering' })
  @ApiResponse({
    status: 200,
    description: 'List of absences with pagination metadata',
  })
  @ApiResponse({ status: 401, description: 'Unauthorized' })
  findAll(
    @Query() query: QueryAbsencesDto,
    @CurrentUser() currentUser: JwtPayload,
  ) {
    return this.absencesService.findAll(query, currentUser);
  }

  @Get('pending')
  @RequirePermissions(Permission.ABSENCES_APPROVE)
  @ApiOperation({ summary: 'Get pending absence requests for approval' })
  @ApiResponse({
    status: 200,
    description: 'List of pending absences',
  })
  @ApiResponse({ status: 401, description: 'Unauthorized' })
  @ApiResponse({ status: 403, description: 'Forbidden - requires approval permission' })
  getPending(@CurrentUser() currentUser: JwtPayload) {
    return this.absencesService.getPending(currentUser);
  }

  @Get('calendar')
  @RequirePermissions(Permission.ABSENCES_VIEW)
  @ApiOperation({ summary: 'Get calendar data for approved absences' })
  @ApiResponse({
    status: 200,
    description: 'Calendar entries for approved absences',
  })
  @ApiResponse({ status: 401, description: 'Unauthorized' })
  getCalendar(
    @Query() query: QueryCalendarDto,
    @CurrentUser() currentUser: JwtPayload,
  ) {
    return this.absencesService.getCalendar(query, currentUser);
  }

  @Get('conflicts')
  @RequirePermissions(Permission.ABSENCES_VIEW)
  @ApiOperation({ summary: 'Check for absence conflicts and team coverage' })
  @ApiResponse({
    status: 200,
    description: 'Conflict check results',
  })
  @ApiResponse({ status: 400, description: 'Bad request - missing required parameters' })
  @ApiResponse({ status: 401, description: 'Unauthorized' })
  checkConflicts(
    @Query() query: QueryConflictsDto,
    @CurrentUser() currentUser: JwtPayload,
  ) {
    return this.absencesService.checkConflicts(query, currentUser);
  }

  @Get('balance/:employeeId')
  @RequirePermissions(Permission.ABSENCES_VIEW)
  @ApiOperation({ summary: 'Get vacation balance for an employee' })
  @ApiParam({ name: 'employeeId', description: 'Employee ID' })
  @ApiResponse({
    status: 200,
    description: 'Vacation balance details',
  })
  @ApiResponse({ status: 401, description: 'Unauthorized' })
  @ApiResponse({ status: 404, description: 'Employee not found' })
  getBalance(
    @Param('employeeId') employeeId: string,
    @Query('year') year?: number,
  ) {
    return this.absencesService.getBalance(employeeId, year);
  }

  @Get(':id')
  @RequirePermissions(Permission.ABSENCES_VIEW)
  @ApiOperation({ summary: 'Get a single absence by ID' })
  @ApiParam({ name: 'id', description: 'Absence ID' })
  @ApiResponse({
    status: 200,
    description: 'Absence details',
  })
  @ApiResponse({ status: 401, description: 'Unauthorized' })
  @ApiResponse({ status: 403, description: 'Forbidden - no access to this absence' })
  @ApiResponse({ status: 404, description: 'Absence not found' })
  findOne(@Param('id') id: string, @CurrentUser() currentUser: JwtPayload) {
    return this.absencesService.findOne(id, currentUser);
  }

  @Put(':id')
  @RequirePermissions(Permission.ABSENCES_CREATE)
  @AuditLog('Absence', 'UPDATE')
  @ApiOperation({ summary: 'Update a pending absence' })
  @ApiParam({ name: 'id', description: 'Absence ID' })
  @ApiResponse({
    status: 200,
    description: 'Absence updated successfully',
  })
  @ApiResponse({ status: 400, description: 'Bad request - only PENDING absences can be updated' })
  @ApiResponse({ status: 401, description: 'Unauthorized' })
  @ApiResponse({ status: 403, description: 'Forbidden' })
  @ApiResponse({ status: 404, description: 'Absence not found' })
  update(
    @Param('id') id: string,
    @Body() updateDto: UpdateAbsenceDto,
    @CurrentUser() currentUser: JwtPayload,
  ) {
    return this.absencesService.update(id, updateDto, currentUser);
  }

  @Delete(':id')
  @RequirePermissions(Permission.ABSENCES_CANCEL)
  @AuditLog('Absence', 'CANCEL')
  @HttpCode(HttpStatus.OK)
  @ApiOperation({ summary: 'Cancel an absence (PENDING or APPROVED)' })
  @ApiParam({ name: 'id', description: 'Absence ID' })
  @ApiResponse({
    status: 200,
    description: 'Absence cancelled successfully',
  })
  @ApiResponse({ status: 400, description: 'Bad request - cannot cancel this absence' })
  @ApiResponse({ status: 401, description: 'Unauthorized' })
  @ApiResponse({ status: 403, description: 'Forbidden' })
  @ApiResponse({ status: 404, description: 'Absence not found' })
  cancel(@Param('id') id: string, @CurrentUser() currentUser: JwtPayload) {
    return this.absencesService.cancel(id, currentUser);
  }

  @Post(':id/approve')
  @RequirePermissions(Permission.ABSENCES_APPROVE)
  @AuditLog('Absence', 'APPROVE')
  @HttpCode(HttpStatus.OK)
  @ApiOperation({ summary: 'Approve a pending absence request' })
  @ApiParam({ name: 'id', description: 'Absence ID' })
  @ApiResponse({
    status: 200,
    description: 'Absence approved successfully',
  })
  @ApiResponse({ status: 400, description: 'Bad request - only PENDING absences can be approved' })
  @ApiResponse({ status: 401, description: 'Unauthorized' })
  @ApiResponse({ status: 403, description: 'Forbidden - cannot approve own absence or no permission' })
  @ApiResponse({ status: 404, description: 'Absence not found' })
  approve(
    @Param('id') id: string,
    @Body() approveDto: ApproveAbsenceDto,
    @CurrentUser() currentUser: JwtPayload,
  ) {
    return this.absencesService.approve(id, approveDto, currentUser);
  }

  @Post(':id/reject')
  @RequirePermissions(Permission.ABSENCES_APPROVE)
  @AuditLog('Absence', 'REJECT')
  @HttpCode(HttpStatus.OK)
  @ApiOperation({ summary: 'Reject a pending absence request' })
  @ApiParam({ name: 'id', description: 'Absence ID' })
  @ApiResponse({
    status: 200,
    description: 'Absence rejected successfully',
  })
  @ApiResponse({ status: 400, description: 'Bad request - only PENDING absences can be rejected' })
  @ApiResponse({ status: 401, description: 'Unauthorized' })
  @ApiResponse({ status: 403, description: 'Forbidden - cannot reject own absence or no permission' })
  @ApiResponse({ status: 404, description: 'Absence not found' })
  reject(
    @Param('id') id: string,
    @Body() rejectDto: RejectAbsenceDto,
    @CurrentUser() currentUser: JwtPayload,
  ) {
    return this.absencesService.reject(id, rejectDto, currentUser);
  }
}
