import { BadRequestException, ForbiddenException } from "@nestjs/common"; /** Insurance company tenant id on the actor JWT (Mongo ObjectId string). */ export function requireActorClientKey(actor: { clientKey?: string }): string { const ck = actor?.clientKey; if (!ck || typeof ck !== "string") { throw new BadRequestException( "Client scope is missing for this account. Insurer/expert users must be bound to an insurance company.", ); } return ck; } export function blameCaseTouchesClient(doc: any, clientKey: string): boolean { const id = String(clientKey); return (doc?.parties ?? []).some( (p: any) => String(p?.person?.clientId ?? "") === id, ); } export function claimCaseTouchesClient(doc: any, clientKey: string): boolean { return String(doc?.owner?.userClientKey ?? "") === String(clientKey); } /** * Field expert–initiated cases may not yet have party clientId filled; the * initiating expert is always scoped to their insurer via JWT. */ export function blameCaseAccessibleToExpert( doc: any, actor: { sub: string; clientKey?: string }, ): boolean { if ( doc.expertInitiated && doc.initiatedByFieldExpertId && String(doc.initiatedByFieldExpertId) === actor.sub ) { return true; } const ck = actor?.clientKey; if (!ck) return false; return blameCaseTouchesClient(doc, ck); } export function assertBlameCaseForExpertTenant( doc: any, actor: { sub: string; clientKey?: string }, ): void { if (!blameCaseAccessibleToExpert(doc, actor)) { throw new ForbiddenException( "This blame case does not belong to your organization.", ); } } export function assertClaimCaseForTenant( doc: any, actor: { clientKey?: string }, ): void { const ck = requireActorClientKey(actor); if (!claimCaseTouchesClient(doc, ck)) { throw new ForbiddenException( "This claim does not belong to your organization.", ); } }