import { z } from "zod"; import { REVIEW_ON_LEVEL_LIMITS, isDiagnosticToken, isRealIsoDate, isDiagnosticPlainRecord, validateReviewOnLevelRequest, calculateReviewOnLevel, replayReviewOnLevel, type ReviewOnLevelRequest, type ReviewOnLevel } from "@actuarial-ts/core"; import { analysisContextSchema, alignedExposureInputSchema, analysisSnapshotSchema, analysisReferenceSchema } from "./reviewContracts.js"; import { parseReviewBoundary } from "./reviewBoundary.js"; const token = z.string().refine(isDiagnosticToken), date = z.string().refine(isRealIsoDate); const historyBase = { reference: analysisReferenceSchema, population: analysisReferenceSchema, knownDate: date, sourceRevisions: z.array(analysisReferenceSchema).min(1) }; export const reviewOnLevelHistorySchema = z.discriminatedUnion("kind", [ z.object({ ...historyBase, kind: z.literal("available"), coverage: z.object({ fromDate: date, untilDate: date, rationale: token }).strict(), ordering: z.literal("effective-date-then-input-order"), changes: z.array(z.object({ id: token, effectiveDate: date, knownDate: date, change: z.number().finite().gt(-1) }).strict()).max(REVIEW_ON_LEVEL_LIMITS.maximumChanges) }).strict(), z.object({ ...historyBase, kind: z.literal("unavailable"), reason: token }).strict(), ]); export const reviewOnLevelRequestSchema = z.object({ id: token, version: token, context: analysisContextSchema, premium: alignedExposureInputSchema, meaning: z.object({ kind: z.literal("earned-premium"), currency: z.string().regex(/^[A-Z]{3}$/), definition: token }).strict(), periods: z.array(z.object({ origin: token, startDate: date, endDate: date, coverage: z.enum(["complete", "partial"]), rationale: token }).strict()).min(1).max(REVIEW_ON_LEVEL_LIMITS.maximumOrigins), history: reviewOnLevelHistorySchema, clock: z.enum(["calendar-year-fraction", "month-start-years"]), targetDate: date, conventions: z.object({ policyTermYears: z.literal(1), writing: z.literal("uniform"), earning: z.literal("uniform"), effectiveOn: z.literal("written-date") }).strict(), order: z.literal("after-existing-premium-adjustments"), application: z.discriminatedUnion("kind", [z.object({ kind: z.literal("standalone") }).strict(), z.object({ kind: z.literal("expected-loss-calibration"), rationale: token }).strict(), z.object({ kind: z.literal("expected-loss-prior"), assumption: analysisReferenceSchema, rationale: token }).strict()]), unavailable: z.enum(["retain-unavailable", "reject"]), declaration: z.object({ actorId: token, knownDate: date, rationale: token }).strict(), snapshots: z.array(analysisSnapshotSchema), limits: z.object({ maximumOrigins: z.number().int().positive().max(REVIEW_ON_LEVEL_LIMITS.maximumOrigins), maximumChanges: z.number().int().positive().max(REVIEW_ON_LEVEL_LIMITS.maximumChanges), maximumContributions: z.number().int().positive().max(REVIEW_ON_LEVEL_LIMITS.maximumContributions), maximumInputCharacters: z.number().int().positive().max(REVIEW_ON_LEVEL_LIMITS.maximumInputCharacters), maximumOutputCharacters: z.number().int().positive().max(REVIEW_ON_LEVEL_LIMITS.maximumOutputCharacters) }).strict(), }).strict(); export function parseReviewOnLevelRequest(input: unknown): ReviewOnLevelRequest { return validateReviewOnLevelRequest(parseReviewBoundary(reviewOnLevelRequestSchema, input) as ReviewOnLevelRequest).request; } export function calculateReviewOnLevelFromInput(input: unknown): ReviewOnLevel { return calculateReviewOnLevel(parseReviewOnLevelRequest(input)); } export function replayReviewOnLevelFromInput(input: unknown): ReviewOnLevel { return replayReviewOnLevel(parseReviewBoundary(z.custom(isDiagnosticPlainRecord), input)); }