import { Controller, Get, Put, Param, Body, UseGuards, Request, HttpStatus, BadRequestException, ForbiddenException, NotFoundException, } from '@nestjs/common'; import { ApiTags, ApiOperation, ApiResponse, ApiBearerAuth } from '@nestjs/swagger'; import { JwtAuthGuard } from '../auth/auth.guard'; import { ImagesService } from './images.service'; import { UpdateFilenameDto, UpdateFilenameResponseDto } from './dto/update-filename.dto'; import { ImageResponseDto, BatchImagesResponseDto } from './dto/image-response.dto'; @ApiTags('images') @Controller('api/image') @UseGuards(JwtAuthGuard) @ApiBearerAuth() export class ImagesController { constructor(private readonly imagesService: ImagesService) {} @Put(':imageId/filename') @ApiOperation({ summary: 'Update image filename', description: 'Updates the proposed filename for a specific image', }) @ApiResponse({ status: HttpStatus.OK, description: 'Filename updated successfully', type: UpdateFilenameResponseDto, }) @ApiResponse({ status: HttpStatus.BAD_REQUEST, description: 'Invalid filename or request data', }) @ApiResponse({ status: HttpStatus.NOT_FOUND, description: 'Image not found', }) @ApiResponse({ status: HttpStatus.FORBIDDEN, description: 'Not authorized to update this image', }) async updateImageFilename( @Param('imageId') imageId: string, @Body() updateFilenameDto: UpdateFilenameDto, @Request() req: any, ): Promise { try { const userId = req.user?.id; if (!userId) { throw new BadRequestException('User not authenticated'); } const result = await this.imagesService.updateFilename( imageId, userId, updateFilenameDto.new_name ); return result; } catch (error) { if ( error instanceof BadRequestException || error instanceof ForbiddenException || error instanceof NotFoundException ) { throw error; } throw new BadRequestException('Failed to update image filename'); } } @Get(':imageId') @ApiOperation({ summary: 'Get image details', description: 'Returns detailed information about a specific image', }) @ApiResponse({ status: HttpStatus.OK, description: 'Image details retrieved successfully', type: ImageResponseDto, }) @ApiResponse({ status: HttpStatus.NOT_FOUND, description: 'Image not found', }) @ApiResponse({ status: HttpStatus.FORBIDDEN, description: 'Not authorized to access this image', }) async getImage( @Param('imageId') imageId: string, @Request() req: any, ): Promise { try { const userId = req.user?.id; if (!userId) { throw new BadRequestException('User not authenticated'); } const image = await this.imagesService.getImage(imageId, userId); return image; } catch (error) { if ( error instanceof BadRequestException || error instanceof ForbiddenException || error instanceof NotFoundException ) { throw error; } throw new BadRequestException('Failed to get image details'); } } @Get('batch/:batchId') @ApiOperation({ summary: 'Get all images in a batch', description: 'Returns all images belonging to a specific batch', }) @ApiResponse({ status: HttpStatus.OK, description: 'Batch images retrieved successfully', type: BatchImagesResponseDto, }) @ApiResponse({ status: HttpStatus.NOT_FOUND, description: 'Batch not found', }) @ApiResponse({ status: HttpStatus.FORBIDDEN, description: 'Not authorized to access this batch', }) async getBatchImages( @Param('batchId') batchId: string, @Request() req: any, ): Promise { try { const userId = req.user?.id; if (!userId) { throw new BadRequestException('User not authenticated'); } const batchImages = await this.imagesService.getBatchImages(batchId, userId); return batchImages; } catch (error) { if ( error instanceof BadRequestException || error instanceof ForbiddenException || error instanceof NotFoundException ) { throw error; } throw new BadRequestException('Failed to get batch images'); } } @Get(':imageId/download') @ApiOperation({ summary: 'Get image download URL', description: 'Returns a presigned URL for downloading the original or processed image', }) @ApiResponse({ status: HttpStatus.OK, description: 'Download URL generated successfully', schema: { type: 'object', properties: { download_url: { type: 'string', example: 'https://storage.example.com/images/processed/image.jpg?expires=...', }, expires_at: { type: 'string', example: '2024-01-01T13:00:00.000Z', }, filename: { type: 'string', example: 'modern-kitchen-renovation.jpg', }, }, }, }) @ApiResponse({ status: HttpStatus.NOT_FOUND, description: 'Image not found', }) @ApiResponse({ status: HttpStatus.FORBIDDEN, description: 'Not authorized to download this image', }) async getImageDownloadUrl( @Param('imageId') imageId: string, @Request() req: any, ): Promise<{ download_url: string; expires_at: string; filename: string; }> { try { const userId = req.user?.id; if (!userId) { throw new BadRequestException('User not authenticated'); } const downloadInfo = await this.imagesService.getImageDownloadUrl(imageId, userId); return downloadInfo; } catch (error) { if ( error instanceof BadRequestException || error instanceof ForbiddenException || error instanceof NotFoundException ) { throw error; } throw new BadRequestException('Failed to generate download URL'); } } @Put(':imageId/approve') @ApiOperation({ summary: 'Approve proposed filename', description: 'Approves the AI-generated proposed filename as the final filename', }) @ApiResponse({ status: HttpStatus.OK, description: 'Filename approved successfully', type: UpdateFilenameResponseDto, }) @ApiResponse({ status: HttpStatus.NOT_FOUND, description: 'Image not found', }) @ApiResponse({ status: HttpStatus.BAD_REQUEST, description: 'No proposed filename to approve', }) async approveFilename( @Param('imageId') imageId: string, @Request() req: any, ): Promise { try { const userId = req.user?.id; if (!userId) { throw new BadRequestException('User not authenticated'); } const result = await this.imagesService.approveProposedFilename(imageId, userId); return result; } catch (error) { if ( error instanceof BadRequestException || error instanceof ForbiddenException || error instanceof NotFoundException ) { throw error; } throw new BadRequestException('Failed to approve filename'); } } @Put(':imageId/revert') @ApiOperation({ summary: 'Revert to original filename', description: 'Reverts the image filename back to the original uploaded filename', }) @ApiResponse({ status: HttpStatus.OK, description: 'Filename reverted successfully', type: UpdateFilenameResponseDto, }) @ApiResponse({ status: HttpStatus.NOT_FOUND, description: 'Image not found', }) async revertFilename( @Param('imageId') imageId: string, @Request() req: any, ): Promise { try { const userId = req.user?.id; if (!userId) { throw new BadRequestException('User not authenticated'); } const result = await this.imagesService.revertToOriginalFilename(imageId, userId); return result; } catch (error) { if ( error instanceof BadRequestException || error instanceof ForbiddenException || error instanceof NotFoundException ) { throw error; } throw new BadRequestException('Failed to revert filename'); } } }