/** * Shared test fixtures — the planning engine (`POST /api/plan/propose`, * `POST /api/plan/apply`) and its nested shapes. */ import type { CostBreakdown, DayCollision, PlanAge4Projection, PlanApplyResponse, PlanChange, PlanProposal, PlanSyncResponse, PlanSyncWithWishResponse, PlanWarning, PoolBalance, ProposedDay, Rejection, ShortfallRemedy, SurplusAdvice, VacationBalance, WindowOutcome, } from '@/types' import { makeLeaveWish } from './mockData' export function makeCostBreakdown(overrides: Partial = {}): CostBreakdown { return { free: 0, vacation: 0, sjukpenning: 0, lagsta: 0, ...overrides } } export function makeShortfallRemedy(overrides: Partial = {}): ShortfallRemedy { return { kind: 'dubbeldag', messageKey: 'planRemedies.example', data: {}, daysFreed: 0, ...overrides, } } export function makeProposedDay(overrides: Partial = {}): ProposedDay { return { date: '2026-06-15', parentPersonalDataUuid: 'pd-a', childId: 'child-1', dayType: 'sjukpenning', isDubbeldag: false, wishId: 'lw-1', reason: 'Sommar', ...overrides, } } export function makeWindowOutcome(overrides: Partial = {}): WindowOutcome { return { wishId: 'lw-1', wishName: 'Sommar', wishNameMessageKey: null, year: 2026, startDate: '2026-06-15', endDate: '2026-07-26', weeksWished: 6, weeksFunded: 6, shortfallDays: 0, strategy: 'parent_swap', messageKey: 'planOutcomes.windowExplanation', data: {}, costBreakdown: makeCostBreakdown({ free: 12, vacation: 19, sjukpenning: 11 }), remedies: [], shiftGainDays: 0, seriesId: null, ...overrides, } } export function makePlanWarning(overrides: Partial = {}): PlanWarning { return { kind: 'days_lost_at_age_4', messageKey: 'planWarnings.days_lost_at_age_4', data: {}, ...overrides, } } export function makePoolBalance(overrides: Partial = {}): PoolBalance { return { parentPersonalDataUuid: 'pd-a', childId: 'child-1', sjukpenningLeft: 310, lagstaLeft: 90, dubbeldagarLeft: 55, ...overrides, } } export function makeVacationBalance(overrides: Partial = {}): VacationBalance { return { parentPersonalDataUuid: 'pd-a', year: 2026, totalDays: 25, savedDaysIn: 0, alreadyUsed: 0, isAssumed: false, ...overrides, } } export function makeSurplusAdvice(overrides: Partial = {}): SurplusAdvice { return { kind: 'wish_more_leave', messageKey: 'planSurplus.wish_more_leave', daysInvolved: 0, data: {}, ...overrides, } } export function makePlanAge4Projection(overrides: Partial = {}): PlanAge4Projection { return { parentPersonalDataUuid: 'pd-a', childId: 'child-1', fourthBirthday: '2029-06-01', projectedLeftAtB4: 0, savableAfterB4: 96, expiringAtB4: 0, ...overrides, } } export function makePlanProposal(overrides: Partial = {}): PlanProposal { return { days: [makeProposedDay()], outcomes: [makeWindowOutcome()], warnings: [], poolBalances: [], vacationBalances: [], surplusAdvice: [], age4Projections: [], ...overrides, } } export function makeDayCollision(overrides: Partial = {}): DayCollision { return { date: '2026-06-15', parentPersonalDataUuid: 'pd-a', childId: 'child-1', existingDayType: 'vacation', proposedDayType: 'sjukpenning', ...overrides, } } export function makeRejection(overrides: Partial = {}): Rejection { return { messageKey: 'planApply.rejection.insufficientBalance', data: {}, ...overrides, } } export function makePlanApplyResponse(overrides: Partial = {}): PlanApplyResponse { return { accepted: true, createdCount: 0, skippedIdenticalCount: 0, skippedFreeCount: 0, replacedCount: 0, collisions: [], rejections: [], createdDays: [], ...overrides, } } /** `POST /api/plan/sync` — one (child, parent, date) slot's delta. See * `PlanChange`'s docstring (src/types/entities.ts) for the `kind` vocabulary. */ export function makePlanChange(overrides: Partial = {}): PlanChange { return { kind: 'added', date: '2028-06-20', parentPersonalDataUuid: 'pd-a', childId: 'child-1', oldDayType: null, newDayType: 'vacation', oldIsDubbeldag: null, newIsDubbeldag: false, oldWishId: null, newWishId: 'lw-1', evicted: false, ...overrides, } } export function makePlanSyncResponse(overrides: Partial = {}): PlanSyncResponse { return { proposal: makePlanProposal(), applyResult: makePlanApplyResponse(), changes: [], ...overrides, } } /** `POST /api/plan/sync-with-wish`'s response — the wish as created/updated * plus the same `PlanSyncResponse` shape `syncPlan()` returns. See * `PlanSyncWithWishResponse`'s doc comment (src/types/api.ts): `wish` is * present even when `sync.applyResult.accepted` is `false`. */ export function makePlanSyncWithWishResponse( overrides: Partial = {}, ): PlanSyncWithWishResponse { return { wish: makeLeaveWish(), sync: makePlanSyncResponse(), ...overrides, } }