import type { ValueObject } from '@core/shared/domain/ValueObject';
import { RacingDomainValidationError } from '../errors/RacingDomainError';
import { MonthlyRecurrencePattern } from './MonthlyRecurrencePattern';
import { WeekdaySet } from './WeekdaySet';

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 ValueObject<RecurrenceStrategyProps> {
  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: ValueObject<RecurrenceStrategyProps>): 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;
    }
  }
}

export { RecurrenceStrategyFactory } from './RecurrenceStrategyFactory';
