import { BadRequestException, Body, Controller, Get, Param, Post, Put, Query, UnauthorizedException, UseGuards, } from "@nestjs/common"; import { ApiBearerAuth, ApiBody, ApiOperation, ApiParam, ApiQuery, ApiTags, } from "@nestjs/swagger"; import { Types } from "mongoose"; import { LocalActorAuthGuard } from "src/auth/guards/actor-local.guard"; import { RolesGuard } from "src/auth/guards/role.guard"; import { Roles } from "src/decorators/roles.decorator"; import { CurrentUser } from "src/decorators/user.decorator"; import { FileRating } from "src/request-management/entities/schema/request-management.schema"; import { RoleEnum } from "src/Types&Enums/role.enum"; import { ExpertInsurerService } from "./expert-insurer.service"; import { CreateBranchDto } from "src/client/dto/create-branch.dto"; import { CreateBlameExpertByInsurerDto, CreateClaimExpertByInsurerDto, } from "./dto/create-insurer-expert.dto"; @Controller("expert-insurer") @ApiTags("expert-insurer-panel") @ApiBearerAuth() @UseGuards(LocalActorAuthGuard, RolesGuard) @Roles(RoleEnum.COMPANY) export class ExpertInsurerController { constructor(private readonly expertInsurerService: ExpertInsurerService) {} @Get("branches") async getInsuranceBranches(@CurrentUser() insurer) { if (!insurer) { throw new UnauthorizedException("Could not identify the current user."); } return await this.expertInsurerService.retrieveInsuranceBranches( insurer.clientKey, ); } @Post("branches") @ApiBody({ type: CreateBranchDto }) async addBranch( @CurrentUser() insurer, @Body() createBranchDto: CreateBranchDto, ) { if (!insurer) { throw new UnauthorizedException("Could not identify the current user."); } return await this.expertInsurerService.addBranch( insurer.clientKey, createBranchDto, ); } @Post("experts/blame") @ApiBody({ type: CreateBlameExpertByInsurerDto }) async addBlameExpert( @CurrentUser() insurer, @Body() body: CreateBlameExpertByInsurerDto, ) { if (!insurer) { throw new UnauthorizedException("Could not identify the current user."); } return this.expertInsurerService.addBlameExpert(insurer.clientKey, body); } @Post("experts/claim") @ApiBody({ type: CreateClaimExpertByInsurerDto }) async addClaimExpert( @CurrentUser() insurer, @Body() body: CreateClaimExpertByInsurerDto, ) { if (!insurer) { throw new UnauthorizedException("Could not identify the current user."); } return this.expertInsurerService.addClaimExpert(insurer.clientKey, body); } @ApiQuery({ name: "page", type: Number }) @ApiQuery({ name: "response_count", type: Number }) @Get("experts/list") async getAllExperts( @Query("page") page: number, @Query("response_count") count: number, @CurrentUser() actor, ) { return await this.expertInsurerService.retrieveAllExpertsOfClient( actor, page, count, ); } @Get("experts/top") @ApiOperation({ summary: "Top blame vs claim experts for this insurer", description: "Response has two arrays: `blameExperts` (roster from expert / blame files) and `claimExperts` (damage-expert roster / claim files). Each item includes `overallAverageRating` derived from ratings stored on those files plus user ratings where present.", }) async getTopExperts(@CurrentUser() actor) { return await this.expertInsurerService.getTopExpertsForClient(actor); } @Get("files") async getAllFiles(@CurrentUser() insurer) { return await this.expertInsurerService.retrieveAllFilesOfClient( insurer.clientKey, ); } @Get("files/:publicId") @ApiParam({ name: "publicId" }) async getFileDetailsByPublicId( @CurrentUser() insurer, @Param("publicId") publicId: string, ) { return await this.expertInsurerService.retrieveFileDetailsByPublicId( insurer.clientKey, publicId, ); } @ApiBody({ description: "One insurer rating for the shared publicId; persisted on claim and/or blame case documents when both exist.", schema: { type: "object", properties: { collisionMethodAccuracy: { type: "number", minimum: 0, maximum: 5, example: 4, description: "تشخیص درست نحوه برخورد", }, evaluationTimeliness: { type: "number", minimum: 0, maximum: 5, example: 3, description: "زمان ارزیابی", }, accidentCauseAccuracy: { type: "number", minimum: 0, maximum: 5, example: 5, description: "تشخیص درست علت تصادف", }, guiltyVehicleIdentification: { type: "number", minimum: 0, maximum: 5, example: 4, description: "تشخیص درست وسیله نقلیه مقصر", }, botRating: { type: "number", minimum: 0, maximum: 5, example: 4, description: "برای امتیاز دادن به عملکرد بات", }, }, required: [ "collisionMethodAccuracy", "evaluationTimeliness", "accidentCauseAccuracy", "guiltyVehicleIdentification", "botRating", ], example: { collisionMethodAccuracy: 4, evaluationTimeliness: 3, accidentCauseAccuracy: 5, guiltyVehicleIdentification: 4, botRating: 4, }, }, }) @ApiParam({ name: "publicId" }) @Put("files/:publicId/rating") async rateExpertsByPublicId( @CurrentUser() insurer, @Param("publicId") publicId: string, @Body() rating: FileRating, ) { return await this.expertInsurerService.rateExpertByPublicId( publicId, rating, insurer.clientKey, ); } @Get("top-files") async getTopFiles(@CurrentUser() insurer) { return await this.expertInsurerService.getTopFilesForClient( insurer.clientKey, ); } @Get("statistics") async getExpertStatistics(@CurrentUser() actor) { return await this.expertInsurerService.getExpertStatisticsReport(actor); } @Get("report/status-counts") @ApiQuery({ name: "from", required: false, description: "Optional start datetime (ISO string)", }) @ApiQuery({ name: "to", required: false, description: "Optional end datetime (ISO string)", }) async getInsurerStatusReport( @CurrentUser() actor, @Query("from") from?: string, @Query("to") to?: string, ) { return await this.expertInsurerService.getInsurerFileStatusCounts( actor, from, to, ); } @ApiParam({ name: "expertId" }) @ApiOperation({ summary: "Files handled by one roster expert (summary rows)", description: "Resolves id against this insurer's `expert` then `damage-expert` roster. Blame branch runs when the id is on the expert roster (field experts). Each item is a small summary (`kind`, ids, statuses, dates)—not full file payloads. Claim matches use final or draft damage-expert reply.", }) @Get("/:expertId") async requestDetail(@CurrentUser() insurer, @Param("expertId") id: string) { if (!Types.ObjectId.isValid(id)) { throw new BadRequestException("Invalid expert ID"); } return await this.expertInsurerService.getAllFilesForInsurerExpert( id, insurer.clientKey, ); } }