import type { IValueObject } from '@core/shared/domain'; import { WeekdaySet } from './WeekdaySet'; import { MonthlyRecurrencePattern } from './MonthlyRecurrencePattern'; import { RacingDomainValidationError } from '../errors/RacingDomainError'; export type WeeklyRecurrenceStrategyProps = { kind: 'weekly'; weekdays: WeekdaySet; }; export type EveryNWeeksRecurrenceStrategyProps = { kind: 'everyNWeeks'; weekdays: WeekdaySet; intervalWeeks: number; }; export type MonthlyNthWeekdayRecurrenceStrategyProps = { kind: 'monthlyNthWeekday'; monthlyPattern: MonthlyRecurrencePattern; }; export type RecurrenceStrategyProps = | WeeklyRecurrenceStrategyProps | EveryNWeeksRecurrenceStrategyProps | MonthlyNthWeekdayRecurrenceStrategyProps; export class RecurrenceStrategy implements IValueObject { private constructor(private readonly strategy: RecurrenceStrategyProps) {} get props(): RecurrenceStrategyProps { return this.strategy; } static weekly(weekdays: WeekdaySet): RecurrenceStrategy { if (weekdays.getAll().length === 0) { throw new RacingDomainValidationError('weekdays are required for weekly recurrence'); } return new RecurrenceStrategy({ kind: 'weekly', weekdays, }); } static everyNWeeks(intervalWeeks: number, weekdays: WeekdaySet): RecurrenceStrategy { if (!Number.isInteger(intervalWeeks) || intervalWeeks <= 0) { throw new RacingDomainValidationError('intervalWeeks must be a positive integer'); } if (weekdays.getAll().length === 0) { throw new RacingDomainValidationError('weekdays are required for everyNWeeks recurrence'); } return new RecurrenceStrategy({ kind: 'everyNWeeks', weekdays, intervalWeeks, }); } static monthlyNthWeekday(pattern: MonthlyRecurrencePattern): RecurrenceStrategy { return new RecurrenceStrategy({ kind: 'monthlyNthWeekday', monthlyPattern: pattern, }); } equals(other: IValueObject): boolean { const otherProps = other.props; if (this.strategy.kind !== otherProps.kind) { return false; } switch (this.strategy.kind) { case 'weekly': return this.strategy.weekdays.equals((otherProps as WeeklyRecurrenceStrategyProps).weekdays); case 'everyNWeeks': const everyN = otherProps as EveryNWeeksRecurrenceStrategyProps; return this.strategy.intervalWeeks === everyN.intervalWeeks && this.strategy.weekdays.equals(everyN.weekdays); case 'monthlyNthWeekday': const monthly = otherProps as MonthlyNthWeekdayRecurrenceStrategyProps; return this.strategy.monthlyPattern.equals(monthly.monthlyPattern); default: return false; } } }