import {
  Controller, Get, Post, Put, Body, Query,
  Param, UseGuards, Req, UseInterceptors,
  UploadedFile, BadRequestException
} from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import { multerConfig } from '../common/config/multer.config';
import { LeavesService } from './leaves.service';
import { CreateLeaveRequestDto } from './dto/create-leave-request.dto';
import { ValidateLeaveDto } from './dto/validate-leave.dto';
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
import { RolesGuard } from '../common/guards/roles.guard';
import { Roles, Role } from '../common/decorators/roles.decorator';
import { AdjustBalanceDto } from './dto/adjust-balance.dto';
import { LeavesAcquisitionService } from './leaves-acquisition.service';
import { PlanningService } from '../planning/planning.service';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { LeaveType } from './entities/leave-type.entity';

@Controller('leaves')
@UseGuards(JwtAuthGuard)
export class LeavesController {
  constructor(
    private readonly leavesService: LeavesService,
    private readonly acquisitionService: LeavesAcquisitionService,
    private readonly planningService: PlanningService,
    @InjectRepository(LeaveType)          
    private readonly leaveTypeRepo: Repository<LeaveType>,
  ) {}

  // Types de congés actifs
  @Get('types')
  getLeaveTypes() {
    return this.leaveTypeRepo.find({
      where: { is_active: true },
      order: { label: 'ASC' },
    });
  }

  // Mes demandes
  @Get('my')
  getMyRequests(@Req() req) {
    return this.leavesService.getMyRequests(req.user.id);
  }

  // Calculer les jours ouvrés
  @Get('calculate')
  calculate(
    @Req() req,
    @Query('start_date') startDate: string,
    @Query('end_date') endDate: string,
    @Query('leave_type_id') leaveTypeId: string,
  ) {
    return this.leavesService.calculateDays(req.user.id, startDate, endDate, +leaveTypeId);
  }

  // Demandes en attente (valideurs)
  @Get('pending')
  @UseGuards(RolesGuard)
  @Roles(Role.TEAM_LEAD, Role.AGENCY_MANAGER, Role.DIRECTOR)
  getPending(@Req() req) {
    return this.leavesService.getPendingForValidator(req.user);
  }

  // Vérifier le seuil avant soumission (appelé par le frontend)
  @Get('check-threshold')
  checkThreshold(
    @Req() req,
    @Query('start_date') startDate: string,
    @Query('end_date') endDate: string,
  ) {
    return this.planningService.checkNewRequestConflict(
      req.user.id,
      startDate,
      endDate,
    );
  }

  // Soumettre une demande (avec ou sans pièce jointe)
  @Post()
  @UseInterceptors(FileInterceptor('attachment', multerConfig))
  create(
    @Req() req,
    @Body() dto: CreateLeaveRequestDto,
    @UploadedFile() file?: Express.Multer.File,
  ) {
    return this.leavesService.createRequestWithFile(req.user, dto, file?.filename);
  }

  // Déclencher manuellement l'acquisition (admin/directeur)
  @Post('acquisition/run')
  @UseGuards(RolesGuard)
  @Roles(Role.DIRECTOR, Role.ADMIN)
  runAcquisition(@Query('year') year?: string) {
    return this.acquisitionService.runAnnualAcquisition(year ? +year : undefined);
  }

  // Prévisualiser l'acquisition d'un collaborateur
  @Get('acquisition/preview/:userId')
  @UseGuards(RolesGuard)
  @Roles(Role.AGENCY_MANAGER, Role.DIRECTOR)
  async previewAcquisition(
    @Param('userId') userId: string,
    @Query('year') year?: string,
  ) {
    const user = await this.leavesService.findUserById(+userId);
    return this.acquisitionService.previewAcquisition(
      user.hired_at,
      user.work_schedule,
      year ? +year : undefined,
    );
  }

  // Tous les soldes d'un collaborateur
  @Get('balance/all/:userId')
  @UseGuards(RolesGuard)
  @Roles(Role.AGENCY_MANAGER, Role.DIRECTOR, Role.ADMIN)
  getAllBalances(@Param('userId') userId: string) {
    return this.leavesService.getAllBalances(+userId);
  }

  // Soldes de toute l'équipe
  @Get('balance/team/:teamId')
  @UseGuards(RolesGuard)
  @Roles(Role.TEAM_LEAD, Role.AGENCY_MANAGER, Role.DIRECTOR)
  getTeamBalances(
    @Param('teamId') teamId: string,
    @Query('leave_type_id') leaveTypeId: string,
  ) {
    return this.leavesService.getTeamBalances(+teamId, +leaveTypeId);
  }

  // Mon solde par type de congé
  @Get('balance/:leaveTypeId')
  getBalance(@Req() req, @Param('leaveTypeId') leaveTypeId: string) {
    return this.leavesService.getBalance(req.user.id, +leaveTypeId);
  }

  // Ajustement manuel du solde
  @Put('balance/:userId/adjust')
  @UseGuards(RolesGuard)
  @Roles(Role.AGENCY_MANAGER, Role.DIRECTOR)
  adjustBalance(
    @Req() req,
    @Param('userId') userId: string,
    @Body() dto: AdjustBalanceDto,
  ) {
    return this.leavesService.adjustBalance(
      req.user,
      +userId,
      dto.leave_type_id,
      dto.adjustment,
      dto.reason,
    );
  }

  // Valider ou rejeter
  @Put(':id/validate')
  @UseGuards(RolesGuard)
  @Roles(Role.TEAM_LEAD, Role.AGENCY_MANAGER, Role.DIRECTOR)
  validate(@Req() req, @Param('id') id: string, @Body() dto: ValidateLeaveDto) {
    return this.leavesService.validate(req.user, +id, dto);
  }

  // Annuler
  @Put(':id/cancel')
  cancel(@Req() req, @Param('id') id: string) {
    return this.leavesService.cancel(req.user, +id);
  }

  // Ajouter/remplacer une pièce jointe sur une demande existante
  @Put(':id/attachment')
  @UseInterceptors(FileInterceptor('attachment', multerConfig))
  uploadAttachment(
    @Req() req,
    @Param('id') id: string,
    @UploadedFile() file: Express.Multer.File,
  ) {
    if (!file) throw new BadRequestException('Aucun fichier reçu');
    return this.leavesService.attachFile(+id, req.user.id, file.filename);
  }

  // Détail d'une demande (propriétaire uniquement)
  @Get(':id')
  getOne(@Req() req, @Param('id') id: string) {
    return this.leavesService.getOne(req.user.id, +id);
  }
}