import { describe, it, expect } from 'vitest';
import { RecurrenceStrategy } from './RecurrenceStrategy';
import { WeekdaySet } from './WeekdaySet';
import { MonthlyRecurrencePattern } from './MonthlyRecurrencePattern';

describe('RecurrenceStrategy', () => {
  describe('weekly', () => {
    it('should create weekly recurrence', () => {
      const weekdays = WeekdaySet.fromArray(['Mon', 'Wed', 'Fri']);
      const strategy = RecurrenceStrategy.weekly(weekdays);
      expect(strategy.props.kind).toBe('weekly');
      expect((strategy.props as { kind: 'weekly'; weekdays: WeekdaySet }).weekdays).toBe(weekdays);
    });

    it('should throw if no weekdays', () => {
      expect(() => WeekdaySet.fromArray([])).toThrow('WeekdaySet requires at least one weekday');
    });
  });

  describe('everyNWeeks', () => {
    it('should create everyNWeeks recurrence', () => {
      const weekdays = WeekdaySet.fromArray(['Tue', 'Thu']);
      const strategy = RecurrenceStrategy.everyNWeeks(2, weekdays);
      expect(strategy.props.kind).toBe('everyNWeeks');
      const props = strategy.props as { kind: 'everyNWeeks'; intervalWeeks: number; weekdays: WeekdaySet };
      expect(props.intervalWeeks).toBe(2);
      expect(props.weekdays).toBe(weekdays);
    });

    it('should throw if intervalWeeks not positive integer', () => {
      const weekdays = WeekdaySet.fromArray(['Mon']);
      expect(() => RecurrenceStrategy.everyNWeeks(0, weekdays)).toThrow('intervalWeeks must be a positive integer');
      expect(() => RecurrenceStrategy.everyNWeeks(-1, weekdays)).toThrow('intervalWeeks must be a positive integer');
      expect(() => RecurrenceStrategy.everyNWeeks(1.5, weekdays)).toThrow('intervalWeeks must be a positive integer');
    });

    it('should throw if no weekdays', () => {
      expect(() => WeekdaySet.fromArray([])).toThrow('WeekdaySet requires at least one weekday');
    });
  });

  describe('monthlyNthWeekday', () => {
    it('should create monthlyNthWeekday recurrence', () => {
      const pattern = MonthlyRecurrencePattern.create(1, 'Mon');
      const strategy = RecurrenceStrategy.monthlyNthWeekday(pattern);
      expect(strategy.props.kind).toBe('monthlyNthWeekday');
      expect((strategy.props as { kind: 'monthlyNthWeekday'; monthlyPattern: MonthlyRecurrencePattern }).monthlyPattern).toBe(pattern);
    });
  });

  describe('equals', () => {
    it('should equal same weekly strategies', () => {
      const weekdays1 = WeekdaySet.fromArray(['Mon', 'Wed']);
      const weekdays2 = WeekdaySet.fromArray(['Mon', 'Wed']);
      const s1 = RecurrenceStrategy.weekly(weekdays1);
      const s2 = RecurrenceStrategy.weekly(weekdays2);
      expect(s1.equals(s2)).toBe(true);
    });

    it('should not equal different weekly strategies', () => {
      const weekdays1 = WeekdaySet.fromArray(['Mon']);
      const weekdays2 = WeekdaySet.fromArray(['Tue']);
      const s1 = RecurrenceStrategy.weekly(weekdays1);
      const s2 = RecurrenceStrategy.weekly(weekdays2);
      expect(s1.equals(s2)).toBe(false);
    });

    it('should equal same everyNWeeks strategies', () => {
      const weekdays1 = WeekdaySet.fromArray(['Fri']);
      const weekdays2 = WeekdaySet.fromArray(['Fri']);
      const s1 = RecurrenceStrategy.everyNWeeks(3, weekdays1);
      const s2 = RecurrenceStrategy.everyNWeeks(3, weekdays2);
      expect(s1.equals(s2)).toBe(true);
    });

    it('should not equal different everyNWeeks strategies', () => {
      const weekdays = WeekdaySet.fromArray(['Sat']);
      const s1 = RecurrenceStrategy.everyNWeeks(2, weekdays);
      const s2 = RecurrenceStrategy.everyNWeeks(4, weekdays);
      expect(s1.equals(s2)).toBe(false);
    });

    it('should equal same monthlyNthWeekday strategies', () => {
      const pattern1 = MonthlyRecurrencePattern.create(2, 'Wed');
      const pattern2 = MonthlyRecurrencePattern.create(2, 'Wed');
      const s1 = RecurrenceStrategy.monthlyNthWeekday(pattern1);
      const s2 = RecurrenceStrategy.monthlyNthWeekday(pattern2);
      expect(s1.equals(s2)).toBe(true);
    });

    it('should not equal different monthlyNthWeekday strategies', () => {
      const pattern1 = MonthlyRecurrencePattern.create(1, 'Thu');
      const pattern2 = MonthlyRecurrencePattern.create(3, 'Thu');
      const s1 = RecurrenceStrategy.monthlyNthWeekday(pattern1);
      const s2 = RecurrenceStrategy.monthlyNthWeekday(pattern2);
      expect(s1.equals(s2)).toBe(false);
    });

    it('should not equal different kinds', () => {
      const weekdays = WeekdaySet.fromArray(['Sun']);
      const pattern = MonthlyRecurrencePattern.create(4, 'Sun');
      const s1 = RecurrenceStrategy.weekly(weekdays);
      const s2 = RecurrenceStrategy.monthlyNthWeekday(pattern);
      expect(s1.equals(s2)).toBe(false);
    });
  });
});