import { resolveClaimOwnerParty, resolveDamagedPartyRow, } from "src/helpers/blame-damaged-party"; import { toJalaliDateAndTime } from "src/helpers/date-jalali"; import { PartyRole } from "src/request-management/entities/schema/partyRole.enum"; import { sanitizeStoredInquiryParticipants } from "src/request-management/inquiry-participant-resolver"; import { InsurerFileReportField, InsurerFileReportSection, InsurerFileReportViewModel, } from "./case-expert-report.types"; import { PR, persianAccidentCondition, persianFieldPath, persianReportValue, persianStatus, } from "./persian-report-labels"; const SKIP_FLATTEN_KEYS = new Set([ "_id", "__v", "history", "workflow", "evidence", "confirmation", "inquiries", "raw", "source", ]); type ReportRecord = Record; type ReportParty = ReportRecord & { role?: string; person?: ReportRecord; insurance?: ReportRecord & { carBodyInsurance?: ReportRecord }; vehicle?: ReportRecord; statement?: ReportRecord; location?: { lat?: number; lon?: number }; participants?: ReportRecord[]; participantRoles?: ReportRecord; }; function asString(value: unknown): string | undefined { if (value === undefined || value === null || value === "") return undefined; if (typeof value === "boolean") return value ? "بله" : "خیر"; if (value instanceof Date) { const [d, t] = toJalaliDateAndTime(value); return `${d} ${t}`; } if (typeof value === "object") { if (typeof (value as { toString?: () => string }).toString === "function") { const s = String(value); if (s !== "[object Object]") return s; } return undefined; } return String(value); } function formatBirthDate(value: unknown): string | undefined { if (value === undefined || value === null || value === "") return undefined; const raw = String(value); if (/^\d{8}$/.test(raw)) { return `${raw.slice(0, 4)}/${raw.slice(4, 6)}/${raw.slice(6, 8)}`; } return raw; } function formatDateTime(value: unknown): string | undefined { if (value === undefined || value === null || value === "") return undefined; const date = value instanceof Date ? value : new Date(value as string | number); if (Number.isNaN(date.getTime())) return asString(value); const [d, t] = toJalaliDateAndTime(date); return `${d} ${t}`; } const PERSIAN_NUMBER_FORMATTER = new Intl.NumberFormat("fa-IR", { maximumFractionDigits: 0, }); function normalizeNumber(value: unknown): number | undefined { if (typeof value === "number") { return Number.isFinite(value) ? value : undefined; } if (typeof value !== "string" || !value.trim()) return undefined; const normalized = value .trim() .replace(/[۰-۹]/g, (digit) => String("۰۱۲۳۴۵۶۷۸۹".indexOf(digit))) .replace(/[٠-٩]/g, (digit) => String("٠١٢٣٤٥٦٧٨٩".indexOf(digit))) .replace(/[٬,\s]/g, ""); const parsed = Number(normalized); return Number.isFinite(parsed) ? parsed : undefined; } function formatToman(value: unknown): string | undefined { if (value === undefined || value === null || value === "") return undefined; const amount = normalizeNumber(value); if (amount === undefined) return asString(value); return `${PERSIAN_NUMBER_FORMATTER.format(amount)} تومان`; } function firstDefined(...values: unknown[]): string | undefined { for (const value of values) { const str = asString(value); if (str) return str; } return undefined; } function normalizeListValue(value: unknown, path = ""): string | undefined { if (!Array.isArray(value) || !value.length) return undefined; const items = value .map( (item) => asString(persianReportValue(path, item)) ?? JSON.stringify(item), ) .filter(Boolean); return items.length ? items.join("، ") : undefined; } function flattenObject( obj: unknown, prefix = "", depth = 0, ): InsurerFileReportField[] { if (obj == null) return []; if (depth > 6) { return [ { label: persianFieldPath(prefix), value: asString(persianReportValue(prefix, obj)), }, ]; } if (Array.isArray(obj)) { if (obj.some((item) => item && typeof item === "object")) { return obj.flatMap((item, index) => flattenObject(item, `${prefix}.${index + 1}`, depth + 1), ); } const value = normalizeListValue(obj, prefix); return value ? [{ label: persianFieldPath(prefix || "items"), value }] : []; } if (typeof obj !== "object") { return [ { label: persianFieldPath(prefix || "value"), value: asString(persianReportValue(prefix || "value", obj)), }, ]; } const rows: InsurerFileReportField[] = []; const objRecord = obj as Record; const hasMapped = objRecord.mapped != null && typeof objRecord.mapped === "object"; for (const [key, value] of Object.entries(objRecord)) { if (SKIP_FLATTEN_KEYS.has(key)) continue; if (key === "raw" && hasMapped) continue; if (value === undefined || value === null || value === "") continue; const path = prefix ? `${prefix}.${key}` : key; if (typeof value === "object" && !(value instanceof Date)) { rows.push(...flattenObject(value, path, depth + 1)); } else { rows.push({ label: persianFieldPath(path), value: asString(persianReportValue(path, value)), }); } } return rows; } function dedupeFields( fields: InsurerFileReportField[], ): InsurerFileReportField[] { const seen = new Set(); const out: InsurerFileReportField[] = []; for (const field of fields) { const value = asString(field.value); if (!value) continue; const key = `${field.label}::${value}`; if (seen.has(key)) continue; seen.add(key); out.push({ label: field.label, value }); } return out; } function filterEmptySections( sections: Array, ): InsurerFileReportSection[] { return sections.filter( (section): section is InsurerFileReportSection => !!section && section.fields.length > 0, ); } function buildSection( title: string, fields: InsurerFileReportField[], withPlaceholder = true, ): InsurerFileReportSection { const deduped = dedupeFields(fields); return { title, fields: deduped.length || !withPlaceholder ? deduped : [{ label: PR.data, value: PR.empty }], }; } function expertNameFromSnapshot(snapshot?: { firstName?: string; lastName?: string; }): string | undefined { if (!snapshot) return undefined; const name = [snapshot.firstName, snapshot.lastName] .filter(Boolean) .join(" "); return name || undefined; } function collectExpertNames( blame?: Record | null, claim?: Record | null, ): string | undefined { const names = new Set(); const blameDecision = (blame?.expert as Record | undefined) ?.decision as Record | undefined; const blameExpert = expertNameFromSnapshot( blameDecision?.expertProfileSnapshot as | { firstName?: string; lastName?: string } | undefined, ); if (blameExpert) names.add(blameExpert); const evaluation = claim?.evaluation as Record | undefined; for (const key of ["damageExpertReplyFinal", "damageExpertReply"] as const) { const reply = evaluation?.[key] as Record | undefined; if (!reply) continue; const actor = (reply.actorDetail as { actorName?: string } | undefined) ?.actorName; if (actor) names.add(actor); const snap = expertNameFromSnapshot( reply.expertProfileSnapshot as | { firstName?: string; lastName?: string } | undefined, ); if (snap) names.add(snap); } return names.size ? [...names].join(", ") : undefined; } function inquiryRoleData( inquiries: Record | undefined, key: string, role?: string, ): Record | undefined { const block = inquiries?.[key] as Record | undefined; const data = block?.data as Record | undefined; if (!data) return undefined; if (role && data[role] && typeof data[role] === "object") { return data[role] as Record; } return data; } function pickInquiryReportPayload( inquiry?: Record, ): Record | undefined { if (!inquiry) return undefined; const mapped = inquiry.mapped; if (mapped && typeof mapped === "object" && !Array.isArray(mapped)) { return mapped as Record; } const { raw: _raw, ...rest } = inquiry; return Object.keys(rest).length ? rest : inquiry; } function resolveReportBlameContext( blame?: Record | null, claim?: Record | null, ): Record | null { if (blame) return blame; const snapshot = claim?.snapshot as Record | undefined; if (!snapshot) return null; return { type: (claim?.blameFileContext as Record | undefined) ?.blameRequestType ?? (snapshot.accident as Record | undefined)?.type, blameStatus: ( claim?.blameFileContext as Record | undefined )?.blameStatus, parties: snapshot.parties, }; } function getPartyRole( party: ReportParty | null | undefined, ): string | undefined { const role = party?.role; return typeof role === "string" ? role : undefined; } function partyKindLabel( party: ReportParty | null | undefined, damagedParty: ReportParty | null, guiltyParty: ReportParty | null, ): string | undefined { if (sameParty(party, damagedParty)) return "damaged"; if (sameParty(party, guiltyParty)) return "guilty"; return undefined; } function partyRoleLabel(role: string | undefined): string | undefined { if (!role) return undefined; if (role === PartyRole.FIRST) return "طرف اول"; if (role === PartyRole.SECOND) return "طرف دوم"; return role; } function statementBoolean(value: unknown): string | undefined { if (typeof value !== "boolean") return undefined; return persianStatus(value); } function sameParty( first: ReportParty | null | undefined, second: ReportParty | null | undefined, ): boolean { if (!first || !second) return false; const firstUserId = first.person?.userId != null ? String(first.person.userId) : ""; const secondUserId = second.person?.userId != null ? String(second.person.userId) : ""; if (firstUserId && secondUserId) return firstUserId === secondUserId; return getPartyRole(first) === getPartyRole(second); } function resolveEvaluationReply( claim?: Record | null, ): Record | undefined { const evaluation = claim?.evaluation as Record | undefined; return ( (evaluation?.damageExpertReplyFinal as | Record | undefined) ?? (evaluation?.damageExpertReply as Record | undefined) ); } function resolveEvaluationSubmittedAt( claim: Record | null | undefined, reply: Record | undefined, ): unknown { if (reply?.submittedAt != null) return reply.submittedAt; const history = Array.isArray(claim?.history) ? claim.history : []; const submittedEvent = [...history] .reverse() .find((event) => ["EXPERT_REPLY_SUBMITTED", "EXPERT_FINAL_REPLY_SUBMITTED"].includes( String((event as Record)?.type ?? ""), ), ) as Record | undefined; return submittedEvent?.timestamp; } function insuranceValueFromCandidates( ...values: unknown[] ): string | undefined { for (const value of values) { if (Array.isArray(value)) { const listValue = normalizeListValue(value); if (listValue) return listValue; continue; } const str = asString(value); if (str) return str; } return undefined; } function buildThirdPartyInsuranceFields( party: ReportParty | null | undefined, blame?: Record | null, claim?: Record | null, ): InsurerFileReportField[] { const role = getPartyRole(party); const direct = (party?.insurance ?? {}) as Record; const blameInquiry = pickInquiryReportPayload( inquiryRoleData( blame?.inquiries as Record | undefined, "thirdParty", role, ), ); const claimInquiry = pickInquiryReportPayload( inquiryRoleData( claim?.inquiries as Record | undefined, "thirdParty", role, ), ); return [ { label: PR.policyNumber, value: insuranceValueFromCandidates( direct.policyNumber, blameInquiry?.policyNumber, blameInquiry?.PolicyNumber, claimInquiry?.policyNumber, claimInquiry?.PolicyNumber, blameInquiry?.ThirdPolicyCode, claimInquiry?.ThirdPolicyCode, ), }, { label: PR.insuranceCompany, value: insuranceValueFromCandidates( direct.company, direct.insurerCompany, blameInquiry?.company, blameInquiry?.CompanyName, claimInquiry?.company, claimInquiry?.CompanyName, ), }, { label: PR.policyStartDate, value: insuranceValueFromCandidates( direct.startDate, blameInquiry?.startDate, blameInquiry?.PolicyStartDate, blameInquiry?.SatrtDate, claimInquiry?.startDate, claimInquiry?.PolicyStartDate, claimInquiry?.SatrtDate, ), }, { label: PR.policyEndDate, value: insuranceValueFromCandidates( direct.endDate, blameInquiry?.endDate, blameInquiry?.PolicyEndDate, blameInquiry?.EndDate, claimInquiry?.endDate, claimInquiry?.PolicyEndDate, claimInquiry?.EndDate, ), }, { label: PR.financialCeiling, value: insuranceValueFromCandidates( direct.financialCeiling, blameInquiry?.financialCeiling, blameInquiry?.FinancialCvrCptl, blameInquiry?.FnCvrCptl, claimInquiry?.financialCeiling, claimInquiry?.FinancialCvrCptl, claimInquiry?.FnCvrCptl, ), }, { label: PR.coverages, value: insuranceValueFromCandidates( direct.coverages, blameInquiry?.coverages, claimInquiry?.coverages, ), }, ]; } function buildCarBodyInsuranceFields( party: ReportParty | null | undefined, blame?: Record | null, claim?: Record | null, ): InsurerFileReportField[] { const role = getPartyRole(party); const direct = (party?.insurance?.carBodyInsurance ?? party?.insurance?.carBody ?? {}) as Record; const blameInquiry = pickInquiryReportPayload( inquiryRoleData( blame?.inquiries as Record | undefined, "carBody", role, ), ); const claimInquiry = pickInquiryReportPayload( inquiryRoleData( claim?.inquiries as Record | undefined, "carBody", role, ), ); const legacy = (blame?.carBodyInsuranceDetail ?? {}) as Record< string, unknown >; return [ { label: PR.policyNumber, value: insuranceValueFromCandidates( direct.policyNumber, legacy.policyNumber, blameInquiry?.policyNumber, blameInquiry?.PolicyNumber, claimInquiry?.policyNumber, claimInquiry?.PolicyNumber, ), }, { label: PR.insuranceCompany, value: insuranceValueFromCandidates( direct.insurerCompany, direct.company, legacy.insurerCompany, blameInquiry?.company, blameInquiry?.CompanyName, claimInquiry?.company, claimInquiry?.CompanyName, ), }, { label: PR.policyStartDate, value: insuranceValueFromCandidates( direct.startDate, legacy.startDate, blameInquiry?.startDate, blameInquiry?.PolicyStartDate, claimInquiry?.startDate, claimInquiry?.PolicyStartDate, ), }, { label: PR.policyEndDate, value: insuranceValueFromCandidates( direct.endDate, legacy.endDate, blameInquiry?.endDate, blameInquiry?.PolicyEndDate, claimInquiry?.endDate, claimInquiry?.PolicyEndDate, ), }, { label: PR.coverages, value: insuranceValueFromCandidates( direct.coverages, legacy.coverages, blameInquiry?.coverages, claimInquiry?.coverages, ), }, ]; } function buildPartyOwnerSection( title: string, party: ReportParty | null | undefined, options?: { claim?: Record | null; useClaimOwnerFallback?: boolean; includeSheba?: boolean; }, ): InsurerFileReportSection | undefined { const person = party?.person as ReportRecord | undefined; const claim = options?.claim; const money = claim?.money as | { sheba?: string; nationalCodeOfInsurer?: string } | undefined; const claimOwner = claim?.owner as { fullName?: string } | undefined; if (!person && !options?.useClaimOwnerFallback) return undefined; return buildSection(title, [ { label: PR.name, value: options?.useClaimOwnerFallback ? firstDefined(person?.fullName, claimOwner?.fullName) : firstDefined(person?.fullName), }, { label: PR.phone, value: asString(person?.phoneNumber) }, { label: PR.nationalCode, value: options?.useClaimOwnerFallback ? firstDefined( person?.nationalCodeOfInsurer, money?.nationalCodeOfInsurer, ) : firstDefined(person?.nationalCodeOfInsurer, person?.nationalCode), }, { label: PR.birthDate, value: formatBirthDate( person?.insurerBirthday ?? person?.birthday ?? person?.driverBirthday, ), }, { label: PR.sheba, value: options?.includeSheba ? money?.sheba : undefined, }, ]); } function buildParticipantRolesSection( title: string, party: ReportParty | null | undefined, ): InsurerFileReportSection | undefined { const participants = sanitizeStoredInquiryParticipants(party?.participants) ?? []; const assignments = party?.participantRoles; if (!assignments || participants.length === 0) return undefined; const roleLabels: Record = { driver: PR.driverRole, vehicleOwner: PR.vehicleOwnerRole, thirdPartyPolicyholder: PR.thirdPartyPolicyholderRole, carBodyPolicyholder: PR.carBodyPolicyholderRole, }; const fields = Object.entries(assignments).map(([role, participantId]) => { const participant = participants.find( (candidate) => String(candidate.participantId) === String(participantId), ); const value = [ asString(participant?.fullName), participant?.nationalCode ? `${PR.nationalCode}: ${asString(participant.nationalCode)}` : undefined, participant?.birthday ? `${PR.birthDate}: ${formatBirthDate(participant.birthday)}` : undefined, participant?.licenseNumber ? `${PR.licenseNumber}: ${asString(participant.licenseNumber)}` : undefined, participant?.hasDrivingLicense != null ? `${PR.hasDrivingLicense}: ${persianStatus(participant.hasDrivingLicense)}` : undefined, participant?.licenseType ? `${PR.licenseType}: ${asString( persianReportValue( "participant.licenseType", participant.licenseType, ), )}` : undefined, ] .filter(Boolean) .join("، "); return { label: roleLabels[role] ?? persianFieldPath(role), value: value || PR.empty, }; }); return buildSection(title, fields, false); } function licenseFieldsFromInquiry(inquiry?: Record): { licenseType?: string; licenseDate?: string; } { if (!inquiry) return {}; return { licenseType: firstDefined( inquiry.LicenseType, inquiry.licenseType, inquiry.Type, inquiry.type, inquiry.LicenseCategory, inquiry.licenseCategory, ), licenseDate: firstDefined( inquiry.IssueDate, inquiry.issueDate, inquiry.LicenseIssueDate, inquiry.licenseIssueDate, inquiry.ExpireDate, inquiry.expireDate, ), }; } function buildDriverSection( damagedParty: ReportParty | null, blame?: Record | null, ): InsurerFileReportSection | undefined { const person = damagedParty?.person as ReportRecord | undefined; if (!person || person.driverIsInsurer !== false) return undefined; const role = damagedParty?.role ?? PartyRole.FIRST; const licenseInquiry = inquiryRoleData( blame?.inquiries as Record | undefined, "drivingLicence", String(role), ); const { licenseType, licenseDate } = licenseFieldsFromInquiry(licenseInquiry); return buildSection(PR.driverSection, [ { label: PR.name, value: asString(person.fullName) }, { label: PR.licenseType, value: asString( persianReportValue( "participant.licenseType", licenseType ?? person.licenseType, ), ) ?? (person.driverLicense ? PR.driverLicense : undefined), }, { label: PR.licenseDate, value: licenseDate ?? asString(person.driverLicense), }, { label: PR.phone, value: asString(person.phoneNumber) }, { label: PR.nationalCode, value: asString(person.nationalCodeOfDriver) }, { label: PR.birthDate, value: formatBirthDate(person.driverBirthday) }, { label: PR.licenseNumber, value: asString(person.driverLicense) }, ]); } function buildPartyVehicleSection( title: string, party: ReportParty | null | undefined, claimVehicle?: Record, ): InsurerFileReportSection | undefined { if (!party && !claimVehicle) return undefined; return buildSection(title, [ ...flattenObject(claimVehicle, "claim.vehicle"), ...flattenObject(party?.vehicle, "party.vehicle"), ]); } function buildPartyStatementSection( title: string, party: ReportParty | null | undefined, damagedParty: ReportParty | null, guiltyParty: ReportParty | null, ): InsurerFileReportSection | undefined { if (!party) return undefined; const statement = (party.statement ?? {}) as ReportRecord; const kind = partyKindLabel(party, damagedParty, guiltyParty); return buildSection(title, [ { label: PR.partyRole, value: partyRoleLabel(getPartyRole(party)), }, { label: PR.name, value: firstDefined(party.person?.fullName), }, { label: PR.admitsGuilt, value: kind === "damaged" ? undefined : statementBoolean(statement.admitsGuilt), }, { label: PR.claimsDamage, value: kind === "guilty" ? undefined : statementBoolean(statement.claimsDamage), }, { label: PR.acceptsExpertOpinion, value: statementBoolean(statement.acceptsExpertOpinion), }, { label: PR.partyDescription, value: asString(statement.description), }, ]); } function buildCaseTimelineSection( overview?: Record | null, claim?: Record | null, ): InsurerFileReportSection { const evaluationReply = resolveEvaluationReply(claim); return buildSection(PR.timelineSection, [ { label: PR.fileRegisteredAt, value: formatDateTime(overview?.createdAt), }, { label: PR.evaluationRegisteredAt, value: formatDateTime( resolveEvaluationSubmittedAt(claim, evaluationReply), ), }, ]); } function buildFanavaranCodesSection( claim?: Record | null, ): InsurerFileReportSection | undefined { if (!claim) return undefined; const sync = (claim.fanavaranSync as Record | undefined) ?? {}; const baseClaim = (sync.baseClaim as Record | undefined) ?? {}; const damageCase = (sync.damageCase as Record | undefined) ?? {}; const expertise = (sync.expertise as Record | undefined) ?? {}; return buildSection(PR.fanavaranSection, [ { label: PR.fanavaranClaimNo, value: firstDefined(claim.claimNo, baseClaim.claimNo), }, { label: PR.fanavaranClaimId, value: firstDefined(claim.claimId, baseClaim.claimId), }, { label: PR.fanavaranDamageCaseId, value: firstDefined( claim.dmgCaseId, damageCase.dmgCaseId, expertise.dmgCaseId, ), }, { label: PR.fanavaranExpertiseId, value: firstDefined(claim.expertiseId, expertise.expertiseId), }, { label: PR.fanavaranPolicyId, value: firstDefined(baseClaim.policyId), }, { label: PR.fanavaranDriverId, value: firstDefined(baseClaim.driverId), }, { label: PR.fanavaranVehicleKindId, value: firstDefined(baseClaim.vehicleKindId), }, { label: PR.fanavaranInsuranceCorpId, value: firstDefined(baseClaim.insuranceCorpId), }, ]); } function buildEvaluationSection( claim?: Record | null, ): InsurerFileReportSection | undefined { if (!claim) return undefined; const reply = resolveEvaluationReply(claim); const actorDetail = reply?.actorDetail as { actorName?: string } | undefined; const snapshotName = expertNameFromSnapshot( reply?.expertProfileSnapshot as | { firstName?: string; lastName?: string } | undefined, ); return buildSection(PR.evaluationSection, [ { label: PR.evaluationResult, value: persianStatus(claim.claimStatus), }, { label: PR.evaluationExpert, value: actorDetail?.actorName ?? snapshotName, }, { label: PR.evaluationSubmittedAt, value: formatDateTime(resolveEvaluationSubmittedAt(claim, reply)), }, { label: PR.evaluationResponse, value: asString(reply?.description), }, ]); } function evaluationPartName(part: ReportRecord): string | undefined { const damage = part.carPartDamage; if (damage && typeof damage === "object" && !Array.isArray(damage)) { const record = damage as ReportRecord; return firstDefined( record.label_fa, record.name, record.part, record.label, part.partId != null ? `${PR.part} ${part.partId}` : undefined, ); } return firstDefined( damage, part.partName, part.partId != null ? `${PR.part} ${part.partId}` : undefined, ); } function evaluationDaghiValue(value: unknown): string | undefined { if (!value || typeof value !== "object" || Array.isArray(value)) { return asString(value); } const daghi = value as ReportRecord; const option = asString(persianReportValue("daghi.option", daghi.option)); const price = formatToman(daghi.price); return [option, price].filter(Boolean).join(" - ") || undefined; } function buildEvaluationPartsSection( claim?: Record | null, ): InsurerFileReportSection | undefined { const reply = resolveEvaluationReply(claim); const parts = Array.isArray(reply?.parts) ? (reply.parts as ReportRecord[]) : []; if (!parts.length) return undefined; const fields = parts.flatMap((part, index) => { const prefix = `${PR.part} ${PERSIAN_NUMBER_FORMATTER.format(index + 1)}`; return [ { label: `${prefix} / ${PR.partName}`, value: evaluationPartName(part) }, { label: `${prefix} / ${PR.damageType}`, value: asString( persianReportValue("evaluation.part.typeOfDamage", part.typeOfDamage), ), }, { label: `${prefix} / ${PR.partPrice}`, value: formatToman(part.price) }, { label: `${prefix} / ${PR.repairSalary}`, value: formatToman(part.salary), }, { label: `${prefix} / ${PR.totalPayment}`, value: formatToman(part.totalPayment), }, { label: `${prefix} / ${PR.factorNeeded}`, value: typeof part.factorNeeded === "boolean" ? persianStatus(part.factorNeeded) : undefined, }, { label: `${prefix} / ${PR.daghi}`, value: evaluationDaghiValue(part.daghi), }, ]; }); return buildSection(PR.evaluationPartsSection, fields, false); } function buildAccidentReportSection( blame?: Record | null, claim?: Record | null, damagedParty?: ReportParty | null, ): InsurerFileReportSection { const statement = damagedParty?.statement as ReportRecord | undefined; const location = damagedParty?.location; const snapshotAccident = ( claim?.snapshot as { accident?: Record } | undefined )?.accident; const blameDecision = (blame?.expert as Record | undefined) ?.decision as Record | undefined; const decisionFields = blameDecision?.fields as | Record | undefined; return buildSection(PR.accidentSection, [ { label: PR.accidentDate, value: asString(statement?.accidentDate) ?? asString(snapshotAccident?.date) ?? asString(blame?.createdAtFormatted) ?? formatDateTime(blame?.createdAt), }, { label: PR.accidentTime, value: asString(statement?.accidentTime) ?? asString(snapshotAccident?.time), }, { label: PR.experts, value: collectExpertNames(blame, claim), }, { label: PR.location, value: location?.lat != null && location?.lon != null ? `${location.lat}، ${location.lon}` : undefined, }, { label: PR.weather, value: persianAccidentCondition( "weather", statement?.weatherCondition ?? snapshotAccident?.weatherCondition, ), }, { label: PR.road, value: persianAccidentCondition( "road", statement?.roadCondition ?? snapshotAccident?.roadCondition, ), }, { label: PR.light, value: persianAccidentCondition( "light", statement?.lightCondition ?? snapshotAccident?.lightCondition, ), }, { label: PR.blameStatus, value: persianStatus(blame?.blameStatus), }, { label: PR.claimStatus, value: persianStatus(claim?.claimStatus), }, { label: PR.expertDecision, value: asString(blameDecision?.description) }, { label: PR.accidentWay, value: asString( (decisionFields?.accidentWay as { label?: string } | undefined) ?.label ?? ( snapshotAccident?.classification as { accidentWay?: { label?: string }; } )?.accidentWay?.label, ), }, { label: PR.accidentReason, value: asString( (decisionFields?.accidentReason as { label?: string } | undefined) ?.label ?? ( snapshotAccident?.classification as { accidentReason?: { label?: string }; } )?.accidentReason?.label, ), }, { label: PR.accidentType, value: asString( (decisionFields?.accidentType as { label?: string } | undefined) ?.label ?? ( snapshotAccident?.classification as { accidentType?: { label?: string }; } )?.accidentType?.label, ), }, { label: PR.partyDescription, value: asString(statement?.description), }, ]); } export function buildInsurerFileReport(file: { overview?: Record; blame?: Record; claim?: Record; }): InsurerFileReportViewModel { const overview = file.overview ?? {}; const claim = file.claim ?? null; const blame = file.blame ?? null; const blameContext = resolveReportBlameContext(blame, claim); const damagedParty = blameContext ? (resolveDamagedPartyRow(blameContext as any) as ReportParty | null) : null; const guiltyParty = blameContext ? (resolveClaimOwnerParty(blameContext as any) as ReportParty | null) : null; const isCarBody = String((blameContext?.type as string | undefined) ?? "") === "CAR_BODY"; const includeGuiltySections = !!guiltyParty && !(isCarBody && sameParty(damagedParty, guiltyParty)); const claimVehicle = claim?.vehicle as Record | undefined; const sections = filterEmptySections([ buildCaseTimelineSection(overview, claim), buildParticipantRolesSection(PR.damagedParticipantsSection, damagedParty), includeGuiltySections ? buildParticipantRolesSection(PR.guiltyParticipantsSection, guiltyParty) : undefined, buildPartyOwnerSection(PR.ownerSection, damagedParty, { claim, useClaimOwnerFallback: true, includeSheba: true, }), includeGuiltySections ? buildPartyOwnerSection(PR.guiltyOwnerSection, guiltyParty) : undefined, buildDriverSection(damagedParty, blameContext), buildSection( PR.damagedThirdPartyInsuranceSection, buildThirdPartyInsuranceFields(damagedParty, blameContext, claim), ), buildSection( PR.damagedCarBodyInsuranceSection, buildCarBodyInsuranceFields(damagedParty, blameContext, claim), ), includeGuiltySections ? buildSection( PR.guiltyThirdPartyInsuranceSection, buildThirdPartyInsuranceFields(guiltyParty, blameContext, claim), ) : undefined, includeGuiltySections ? buildSection( PR.guiltyCarBodyInsuranceSection, buildCarBodyInsuranceFields(guiltyParty, blameContext, claim), ) : undefined, buildPartyVehicleSection( PR.damagedVehicleSection, damagedParty, claimVehicle, ), includeGuiltySections ? buildPartyVehicleSection(PR.guiltyVehicleSection, guiltyParty) : undefined, buildPartyStatementSection( PR.damagedStatementSection, damagedParty, damagedParty, guiltyParty, ), includeGuiltySections ? buildPartyStatementSection( PR.guiltyStatementSection, guiltyParty, damagedParty, guiltyParty, ) : undefined, buildFanavaranCodesSection(claim), buildEvaluationSection(claim), buildEvaluationPartsSection(claim), buildAccidentReportSection(blameContext, claim, damagedParty), ]); return { title: PR.reportTitle, publicId: asString(overview.publicId) ?? PR.empty, requestNo: asString(overview.requestNo), sections, }; }