import {
  BadRequestException,
  Body,
  Controller,
  Delete,
  Get,
  MaxFileSizeValidator,
  Param,
  ParseFilePipe,
  ParseIntPipe,
  Post,
  Put,
  Req,
  UploadedFile,
  UseGuards,
  UseInterceptors,
} from '@nestjs/common';
import { ParentType, Trimester, UserRole } from '@prisma/client';
import { FileInterceptor } from '@nestjs/platform-express';
import { diskStorage } from 'multer';
import { extname, join } from 'path';
import { existsSync, mkdirSync } from 'fs';
import type { AuthenticatedRequest } from '../auth/jwt-auth.guard';
import { JwtAuthGuard } from '../auth/jwt-auth.guard';
import { Roles } from '../auth/roles.decorator';
import { RolesGuard } from '../auth/roles.guard';
import { IndicesService } from './indices.service';
import { UpsertParentIndicesDto } from './dto/upsert-parent-indices.dto';
import { UpsertBabyIndicesDto, UpsertBabyTrimesterDto } from './dto/upsert-baby-indices.dto';

const uploadsDir = join(process.cwd(), 'uploads');

const storage = diskStorage({
  destination: (_req, _file, callback) => {
    if (!existsSync(uploadsDir)) {
      mkdirSync(uploadsDir, { recursive: true });
    }
    callback(null, uploadsDir);
  },
  filename: (_req, file, callback) => {
    const uniqueSuffix = `${Date.now()}-${Math.round(Math.random() * 1e9)}`;
    callback(null, `indices-${uniqueSuffix}${extname(file.originalname)}`);
  },
});

@Controller('projects/:projectId/indices')
@UseGuards(JwtAuthGuard)
export class IndicesController {
  constructor(private readonly indicesService: IndicesService) {}

  @Get()
  getProjectIndices(
    @Req() request: AuthenticatedRequest,
    @Param('projectId') projectId: string,
  ) {
    return this.indicesService.getProjectIndices(request.user!.sub, projectId);
  }

  @Put('parents/:parentType')
  @UseGuards(JwtAuthGuard, RolesGuard)
  @Roles(UserRole.ADMIN)
  upsertParentIndices(
    @Req() request: AuthenticatedRequest,
    @Param('projectId') projectId: string,
    @Param('parentType') parentType: ParentType,
    @Body() dto: UpsertParentIndicesDto,
  ) {
    return this.indicesService.upsertParentIndices(request.user!.sub, projectId, parentType, dto);
  }

  @Post('parents/:parentType/photos')
  @UseGuards(JwtAuthGuard, RolesGuard)
  @Roles(UserRole.ADMIN)
  @UseInterceptors(FileInterceptor('file', { storage }))
  addParentPhoto(
    @Req() request: AuthenticatedRequest,
    @Param('projectId') projectId: string,
    @Param('parentType') parentType: ParentType,
    @UploadedFile(
      new ParseFilePipe({
        validators: [new MaxFileSizeValidator({ maxSize: 5 * 1024 * 1024 })],
        fileIsRequired: true,
      }),
    )
    file: Express.Multer.File,
  ) {
    const allowed = ['image/png', 'image/jpeg', 'image/jpg', 'image/webp'];
    if (!allowed.includes(file.mimetype)) {
      throw new BadRequestException('Format non supporté. Utilisez PNG, JPG ou WEBP.');
    }
    return this.indicesService.addParentPhoto(
      request.user!.sub,
      projectId,
      parentType,
      `/uploads/${file.filename}`,
    );
  }

  @Delete('parents/:parentType/photos/:photoId')
  @UseGuards(JwtAuthGuard, RolesGuard)
  @Roles(UserRole.ADMIN)
  deleteParentPhoto(
    @Req() request: AuthenticatedRequest,
    @Param('projectId') projectId: string,
    @Param('parentType') parentType: ParentType,
    @Param('photoId') photoId: string,
  ) {
    return this.indicesService.deleteParentPhoto(request.user!.sub, projectId, parentType, photoId);
  }

  @Put('babies/:babyIndex')
  @UseGuards(JwtAuthGuard, RolesGuard)
  @Roles(UserRole.ADMIN)
  upsertBabyIndices(
    @Req() request: AuthenticatedRequest,
    @Param('projectId') projectId: string,
    @Param('babyIndex', ParseIntPipe) babyIndex: number,
    @Body() dto: UpsertBabyIndicesDto,
  ) {
    return this.indicesService.upsertBabyIndices(request.user!.sub, projectId, babyIndex, dto);
  }

  @Put('babies/:babyIndex/trimesters/:trimester')
  @UseGuards(JwtAuthGuard, RolesGuard)
  @Roles(UserRole.ADMIN)
  upsertBabyTrimester(
    @Req() request: AuthenticatedRequest,
    @Param('projectId') projectId: string,
    @Param('babyIndex', ParseIntPipe) babyIndex: number,
    @Param('trimester') trimester: Trimester,
    @Body() dto: UpsertBabyTrimesterDto,
  ) {
    return this.indicesService.upsertBabyTrimester(
      request.user!.sub,
      projectId,
      babyIndex,
      trimester,
      dto,
    );
  }

  @Post('babies/:babyIndex/trimesters/:trimester/photos')
  @UseGuards(JwtAuthGuard, RolesGuard)
  @Roles(UserRole.ADMIN)
  @UseInterceptors(FileInterceptor('file', { storage }))
  addTrimesterPhoto(
    @Req() request: AuthenticatedRequest,
    @Param('projectId') projectId: string,
    @Param('babyIndex', ParseIntPipe) babyIndex: number,
    @Param('trimester') trimester: Trimester,
    @UploadedFile(
      new ParseFilePipe({
        validators: [new MaxFileSizeValidator({ maxSize: 5 * 1024 * 1024 })],
        fileIsRequired: true,
      }),
    )
    file: Express.Multer.File,
  ) {
    const allowed = ['image/png', 'image/jpeg', 'image/jpg', 'image/webp'];
    if (!allowed.includes(file.mimetype)) {
      throw new BadRequestException('Format non supporté. Utilisez PNG, JPG ou WEBP.');
    }
    return this.indicesService.addTrimesterPhoto(
      request.user!.sub,
      projectId,
      babyIndex,
      trimester,
      `/uploads/${file.filename}`,
    );
  }

  @Delete('babies/:babyIndex/trimesters/:trimester/photos/:photoId')
  @UseGuards(JwtAuthGuard, RolesGuard)
  @Roles(UserRole.ADMIN)
  deleteTrimesterPhoto(
    @Req() request: AuthenticatedRequest,
    @Param('projectId') projectId: string,
    @Param('babyIndex', ParseIntPipe) babyIndex: number,
    @Param('trimester') trimester: Trimester,
    @Param('photoId') photoId: string,
  ) {
    return this.indicesService.deleteTrimesterPhoto(
      request.user!.sub,
      projectId,
      babyIndex,
      trimester,
      photoId,
    );
  }
}
