<?php
/**
 * Supported recurrence rule subset.
 *
 * @package ScheduledChanges
 */

namespace ScheduledChanges\Scheduler;

use ScheduledChanges\Domain\Shared\NamedTimezone;
use ScheduledChanges\Domain\Shared\UtcTimestamp;

/**
 * Parses fixed hourly, daily, and weekly RFC 5545-style recurrence rules.
 */
final class RecurrenceRule {
	private string $frequency;
	private int $interval;
	private function __construct( string $frequency, int $interval ) {
		$this->frequency = $frequency;
		$this->interval  = $interval;
	}

	public static function parse( string $rule ): self {
		$parts = array();
		foreach ( explode( ';', strtoupper( trim( $rule ) ) ) as $part ) {
			$pair = explode( '=', $part, 2 );
			if ( 2 === count( $pair ) ) {
				$parts[ $pair[0] ] = $pair[1];
			}
		}

		$frequency = (string) ( $parts['FREQ'] ?? '' );
		$interval  = (int) ( $parts['INTERVAL'] ?? 1 );

		if ( ! in_array( $frequency, array( 'HOURLY', 'DAILY', 'WEEKLY' ), true ) || $interval <= 0 ) {
			throw new \InvalidArgumentException(
				'Recurrence must use FREQ=HOURLY, DAILY, or WEEKLY with a positive INTERVAL.'
			);
		}

		$unknown = array_diff( array_keys( $parts ), array( 'FREQ', 'INTERVAL' ) );
		if ( array() !== $unknown ) {
			throw new \InvalidArgumentException( 'Recurrence contains unsupported rule parts.' );
		}

		return new self( $frequency, $interval );
	}

	public function next( UtcTimestamp $occurrence, NamedTimezone $timezone ): UtcTimestamp {
		$local = $occurrence->native()->setTimezone( $timezone->native() );
		switch ( $this->frequency ) {
			case 'HOURLY':
				$unit = 'hour';
				break;
			case 'DAILY':
				$unit = 'day';
				break;
			case 'WEEKLY':
				$unit = 'week';
				break;
			default:
				throw new \LogicException( 'Unsupported recurrence frequency.' );
		}
		$next = $local
			->modify( '+' . $this->interval . ' ' . $unit )
			->setTimezone( new \DateTimeZone( 'UTC' ) );

		return new UtcTimestamp( $next );
	}
}
