import { BadRequestException, Body, Controller, Get, Param, Post, Query, UseGuards, } from "@nestjs/common"; import { ApiBearerAuth, ApiOperation, ApiParam, ApiQuery, ApiTags, } from "@nestjs/swagger"; import { LocalActorAuthGuard } from "src/auth/guards/actor-local.guard"; import { ClaimRequestManagementService } from "src/claim-request-management/claim-request-management.service"; import { FANAVARAN_CLIENT_KEYS, FANAVARAN_CLIENT_SWAGGER_ENUM, isFanavaranClientKey, listFanavaranClientProfiles, normalizeFanavaranClientKey, resolveFanavaranClientKey, } from "src/core/config/fanavaran-client.config"; @ApiTags("fanavaran") @Controller("v2/fanavaran") @ApiBearerAuth() @UseGuards(LocalActorAuthGuard) export class FanavaranController { constructor( private readonly claimRequestManagementService: ClaimRequestManagementService, ) {} @Get("clients") @ApiOperation({ summary: "List supported Fanavaran insurance clients", description: "Returns configured Fanavaran tenants (parsian, tejaratno, moallem) and which client is active for this deployment.", }) listClients() { const activeClient = resolveFanavaranClientKey(); return { activeClient, clients: listFanavaranClientProfiles().map((profile) => ({ key: profile.key, defaults: profile.defaults, isActive: profile.key === activeClient, })), }; } @Get(":client/claim-cases/:claimCaseId/base-claim/preview") @ApiOperation({ summary: "Preview Fanavaran base claim create payload", description: "Builds the GEN.03 payload from local claim/blame data. Fanavaran-sourced PolicyId is resolve-once: first call may inquire and caches on the claim; later calls reuse the cache. Auth token is shared until Asia/Tehran midnight. Pass forceRefreshPolicy=true to re-inquire.", }) @ApiParam({ name: "client", description: "Fanavaran tenant key", enum: FANAVARAN_CLIENT_SWAGGER_ENUM, }) @ApiParam({ name: "claimCaseId", description: "Claim case MongoDB ObjectId", }) @ApiQuery({ name: "debug", required: false, description: "When true, returns payload plus mapping debug steps", }) @ApiQuery({ name: "forceRefreshPolicy", required: false, description: "When true, ignores cached PolicyId and performs a live Fanavaran policy inquiry again. Do not pass this from normal UI loads.", }) @ApiQuery({ name: "resolvePolicy", required: false, deprecated: true, description: "Deprecated. Ignored for cache-busting. PolicyId is resolve-once from fanavaranSync.baseClaim.policyId; use forceRefreshPolicy=true only to re-inquire.", }) async preview( @Param("client") client: string, @Param("claimCaseId") claimCaseId: string, @Query("debug") debug?: string, @Query("forceRefreshPolicy") forceRefreshPolicy?: string, @Query("resolvePolicy") _resolvePolicy?: string, ) { const clientKey = this.parseClientParam(client); // IMPORTANT: resolvePolicy must NOT force a live inquiry. Older UI clients // send resolvePolicy=true on every preview load; that used to defeat the // PolicyId cache and re-Login Fanavaran on every click. return await this.claimRequestManagementService.previewFanavaranSubmitV2( claimCaseId, clientKey, { debug: debug === "1" || debug === "true", forceRefreshPolicy: forceRefreshPolicy === "1" || forceRefreshPolicy === "true", requirePolicyId: false, }, ); } @Post(":client/claim-cases/:claimCaseId/base-claim/submit") @ApiOperation({ summary: "Submit Fanavaran base claim create request", description: "Authenticates with the selected tenant credentials and submits the GEN.03 base claim create request. Stores returned Id as claimId and ClaimNo when present.", }) @ApiParam({ name: "client", description: "Fanavaran tenant key", enum: FANAVARAN_CLIENT_SWAGGER_ENUM, }) @ApiParam({ name: "claimCaseId", description: "Claim case MongoDB ObjectId", }) async submit( @Param("client") client: string, @Param("claimCaseId") claimCaseId: string, @Body() body?: Record, ) { const clientKey = this.parseClientParam(client); return await this.claimRequestManagementService.submitFanavaranV2( claimCaseId, clientKey, body && Object.keys(body).length > 0 ? body : undefined, ); } @Get(":client/claim-cases/:claimCaseId/damage-case/preview") @ApiOperation({ summary: "Preview Fanavaran damage-case payload", description: "Builds the GEN.12 damaged vehicle/person case payload without calling Fanavaran. Requires selected damaged parts; submit requires a Fanavaran claimId.", }) @ApiParam({ name: "client", description: "Fanavaran tenant key", enum: FANAVARAN_CLIENT_SWAGGER_ENUM, }) @ApiParam({ name: "claimCaseId", description: "Claim case MongoDB ObjectId", }) async previewDamageCase( @Param("client") client: string, @Param("claimCaseId") claimCaseId: string, ) { const clientKey = this.parseClientParam(client); return await this.claimRequestManagementService.previewFanavaranDamageCaseV2( claimCaseId, clientKey, ); } @Post(":client/claim-cases/:claimCaseId/damage-case/submit") @ApiOperation({ summary: "Submit Fanavaran damage-case request", description: "Submits the GEN.12 dmg-cases request. If base claim (claimId) is missing, soft-ensures GEN.03 base claim first, then submits damage. Skips when dmgCaseId already exists.", }) @ApiParam({ name: "client", description: "Fanavaran tenant key", enum: FANAVARAN_CLIENT_SWAGGER_ENUM, }) @ApiParam({ name: "claimCaseId", description: "Claim case MongoDB ObjectId", }) async submitDamageCase( @Param("client") client: string, @Param("claimCaseId") claimCaseId: string, @Body() body?: Record, ) { const clientKey = this.parseClientParam(client); return await this.claimRequestManagementService.submitFanavaranDamageCaseV2( claimCaseId, clientKey, body && Object.keys(body).length > 0 ? body : undefined, ); } @Get(":client/claim-cases/:claimCaseId/attachments/preview") @ApiOperation({ summary: "Preview Fanavaran attachment upload plan", description: "Lists local required-document and captured damage images that would be sent to GEN.07. Shows which images are already recorded as uploaded to Fanavaran.", }) @ApiParam({ name: "client", description: "Fanavaran tenant key", enum: FANAVARAN_CLIENT_SWAGGER_ENUM, }) @ApiParam({ name: "claimCaseId", description: "Claim case MongoDB ObjectId", }) async previewAttachments( @Param("client") client: string, @Param("claimCaseId") claimCaseId: string, ) { const clientKey = this.parseClientParam(client); return await this.claimRequestManagementService.previewFanavaranAttachmentsV2( claimCaseId, clientKey, ); } @Post(":client/claim-cases/:claimCaseId/attachments/submit") @ApiOperation({ summary: "Submit missing Fanavaran attachments", description: "Uploads every local image that does not already have a recorded successful GEN.07 Fanavaran file upload. Uses one multipart request per image.", }) @ApiParam({ name: "client", description: "Fanavaran tenant key", enum: FANAVARAN_CLIENT_SWAGGER_ENUM, }) @ApiParam({ name: "claimCaseId", description: "Claim case MongoDB ObjectId", }) async submitAttachments( @Param("client") client: string, @Param("claimCaseId") claimCaseId: string, ) { const clientKey = this.parseClientParam(client); return await this.claimRequestManagementService.submitFanavaranAttachmentsV2( claimCaseId, clientKey, ); } @Get(":client/claim-cases/:claimCaseId/expertise/preview") @ApiOperation({ summary: "Preview Fanavaran expertise payload", description: "Builds the GEN.08 expertise payload from the active damage expert reply, price-drop data, and Fanavaran lookup mappings without calling Fanavaran.", }) @ApiParam({ name: "client", description: "Fanavaran tenant key", enum: FANAVARAN_CLIENT_SWAGGER_ENUM, }) @ApiParam({ name: "claimCaseId", description: "Claim case MongoDB ObjectId", }) async previewExpertise( @Param("client") client: string, @Param("claimCaseId") claimCaseId: string, ) { const clientKey = this.parseClientParam(client); return await this.claimRequestManagementService.previewFanavaranExpertiseV2( claimCaseId, clientKey, ); } @Post(":client/claim-cases/:claimCaseId/expertise/submit") @ApiOperation({ summary: "Submit Fanavaran expertise request", description: "Submits the GEN.08 expertise payload for a claim with existing Fanavaran claimId and dmgCaseId. Stores returned Id as local expertiseId.", }) @ApiParam({ name: "client", description: "Fanavaran tenant key", enum: FANAVARAN_CLIENT_SWAGGER_ENUM, }) @ApiParam({ name: "claimCaseId", description: "Claim case MongoDB ObjectId", }) async submitExpertise( @Param("client") client: string, @Param("claimCaseId") claimCaseId: string, @Body() body?: Record, ) { const clientKey = this.parseClientParam(client); return await this.claimRequestManagementService.submitFanavaranExpertiseV2( claimCaseId, clientKey, body && Object.keys(body).length > 0 ? body : undefined, ); } private parseClientParam(client: string) { if (!isFanavaranClientKey(client)) { throw new BadRequestException( `Invalid Fanavaran client "${client}". Expected one of: ${FANAVARAN_CLIENT_KEYS.join(", ")}`, ); } return normalizeFanavaranClientKey(client); } }