import { extname } from "node:path"; import { Controller, Post, Body, Param, UseGuards, Get, Query, UseInterceptors, UploadedFile, } from "@nestjs/common"; import { FileInterceptor, } from "@nestjs/platform-express"; import { diskStorage } from "multer"; import { ApiBearerAuth, ApiBody, ApiParam, ApiQuery, ApiTags, ApiOperation, ApiResponse, ApiConsumes, } from "@nestjs/swagger"; import { LocalActorAuthGuard } from "src/auth/guards/actor-local.guard"; import { RolesGuard } from "src/auth/guards/role.guard"; import { CurrentUser } from "src/decorators/user.decorator"; import { Roles } from "src/decorators/roles.decorator"; import { RoleEnum } from "src/Types&Enums/role.enum"; import { RequestManagementService } from "./request-management.service"; import { CreateExpertInitiatedFileDto } from "./dto/expert-initiated.dto"; import { ExpertCompleteThirdPartyFormDto } from "./dto/expert-complete-third-party-form.dto"; import { ExpertCompleteCarBodyFormDto } from "./dto/expert-complete-car-body-form.dto"; import { ExpertAccidentFieldsDto } from "./dto/expert-accident-fields.dto"; @ApiTags("expert-initiated-blame") @Controller("expert-initiated-blame") @ApiBearerAuth() @UseGuards(LocalActorAuthGuard, RolesGuard) @Roles(RoleEnum.EXPERT, RoleEnum.DAMAGE_EXPERT) export class ExpertInitiatedController { constructor( private readonly requestManagementService: RequestManagementService, ) {} @Post("create") @ApiOperation({ summary: "Create expert-initiated blame file", description: "Expert creates an initial incomplete blame file. Can be IN_PERSON (expert fills all info) or LINK (expert sends link to users).", }) @ApiBody({ type: CreateExpertInitiatedFileDto }) @ApiResponse({ status: 201, description: "File created successfully", schema: { type: "object", properties: { requestId: { type: "string" }, }, }, }) async createExpertInitiatedFile( @CurrentUser() expert: any, @Body() dto: CreateExpertInitiatedFileDto, ) { return await this.requestManagementService.createExpertInitiatedFile( expert, dto, ); } @Post("complete-form-third-party/:requestId") @ApiOperation({ summary: "Expert completes all information for IN_PERSON THIRD_PARTY file", description: "Expert fills all information at once for IN_PERSON THIRD_PARTY files. " + "Includes first party, second party, and guilty party selection. " + "Video and voice uploads are handled separately.", }) @ApiParam({ name: "requestId", description: "ID of the expert-initiated IN_PERSON THIRD_PARTY file", }) @ApiBody({ type: ExpertCompleteThirdPartyFormDto }) @ApiResponse({ status: 200, description: "Form completed successfully. File is now ready for user signatures.", }) async completeThirdPartyForm( @CurrentUser() expert: any, @Param("requestId") requestId: string, @Body() formData: ExpertCompleteThirdPartyFormDto, ) { return await this.requestManagementService.expertCompleteThirdPartyForm( expert, requestId, formData, ); } @Post("complete-form-car-body/:requestId") @ApiOperation({ summary: "Expert completes all information for IN_PERSON CAR_BODY file", description: "Expert fills all information at once for IN_PERSON CAR_BODY files. " + "Includes first party data and carBodyForm. " + "Video and voice uploads are handled separately.", }) @ApiParam({ name: "requestId", description: "ID of the expert-initiated IN_PERSON CAR_BODY file", }) @ApiBody({ type: ExpertCompleteCarBodyFormDto }) @ApiResponse({ status: 200, description: "Form completed successfully. File is now ready for user signature.", }) async completeCarBodyForm( @CurrentUser() expert: any, @Param("requestId") requestId: string, @Body() formData: ExpertCompleteCarBodyFormDto, ) { return await this.requestManagementService.expertCompleteCarBodyForm( expert, requestId, formData, ); } @Post("upload-video/:requestId") @ApiOperation({ summary: "Expert uploads video for expert-initiated file", description: "Expert uploads a single video file for the entire blame file. " + "Only one video is needed per file (not per party). " + "Only works for expert-initiated files.", }) @ApiParam({ name: "requestId", description: "ID of the expert-initiated file", }) @ApiConsumes("multipart/form-data") @ApiBody({ schema: { type: "object", properties: { file: { type: "string", format: "binary", }, }, }, }) @UseInterceptors( FileInterceptor("file", { limits: { fileSize: 20 * 1024 * 1024, // 20MB }, storage: diskStorage({ destination: "./files/video", filename: (req, file, callback) => { const unique = Date.now(); const ex = extname(file.originalname); const filename = `expert-${file.originalname}-${unique}${ex}`; callback(null, filename); }, }), }), ) @ApiResponse({ status: 200, description: "Video uploaded successfully", }) async uploadVideo( @CurrentUser() expert: any, @Param("requestId") requestId: string, @UploadedFile() file?: Express.Multer.File, ) { return await this.requestManagementService.expertUploadVideo( expert, requestId, file, ); } @Post("upload-voice/:requestId") @ApiOperation({ summary: "Expert uploads voice for expert-initiated file", description: "Expert uploads a single voice file for the entire blame file. " + "Only one voice is needed per file (not per party). " + "Only works for expert-initiated files.", }) @ApiParam({ name: "requestId", description: "ID of the expert-initiated file", }) @ApiConsumes("multipart/form-data") @ApiBody({ schema: { type: "object", properties: { voice: { type: "string", format: "binary", }, }, }, }) @UseInterceptors( FileInterceptor("voice", { limits: { fileSize: 10 * 1024 * 1024, // 10MB }, storage: diskStorage({ destination: "./files/voice", filename: (req, file, callback) => { const unique = Date.now(); const ex = extname(file.originalname); const flname = file.originalname.split(".")[0]; const filename = `expert-${flname}-${unique}${ex}`; callback(null, filename); }, }), }), ) @ApiResponse({ status: 200, description: "Voice uploaded successfully", }) async uploadVoice( @CurrentUser() expert: any, @Param("requestId") requestId: string, @UploadedFile() voice?: Express.Multer.File, ) { return await this.requestManagementService.expertUploadVoice( expert, requestId, voice, ); } @Post("add-accident-fields/:requestId") @ApiOperation({ summary: "Expert adds accident fields to expert-initiated file", description: "Expert adds accident way, reason, and type fields to an expert-initiated file. " + "Can be used for both IN_PERSON and LINK-based files. " + "If expertSubmitReply already exists, updates the fields. Otherwise, creates a new expertSubmitReply.", }) @ApiParam({ name: "requestId", description: "ID of the expert-initiated file", }) @ApiBody({ type: ExpertAccidentFieldsDto }) @ApiResponse({ status: 200, description: "Accident fields added successfully", }) async addAccidentFields( @CurrentUser() expert: any, @Param("requestId") requestId: string, @Body() fields: ExpertAccidentFieldsDto, ) { return await this.requestManagementService.expertAddAccidentFields( expert, requestId, fields, ); } }