<?php
/**
 * Execution retry policy.
 *
 * @package ScheduledChanges
 */

namespace ScheduledChanges\Execution;

use ScheduledChanges\Domain\Run\FailureClassification;

/**
 * Bounded exponential retry policy for explicitly temporary failures.
 */
final class RetryPolicy {
	public const MAX_ATTEMPTS = 3;

	public function retryable( string $classification, int $attempt_number ): bool {
		return $attempt_number < self::MAX_ATTEMPTS
			&& $this->supportsClassification( $classification );
	}

	public function exhausted( string $classification, int $attempt_number ): bool {
		return $attempt_number >= self::MAX_ATTEMPTS
			&& $this->supportsClassification( $classification );
	}

	public function delaySeconds( int $next_attempt_number ): int {
		if ( $next_attempt_number <= 1 ) {
			throw new \InvalidArgumentException( 'Retry attempts must start at attempt two.' );
		}

		return min( 300, 15 * ( 2 ** ( $next_attempt_number - 2 ) ) );
	}

	private function supportsClassification( string $classification ): bool {
		return in_array(
			$classification,
			array(
				FailureClassification::TEMPORARY_PROVIDER,
				FailureClassification::LOCK_CONTENTION,
				FailureClassification::EXTERNAL_TIMEOUT,
				FailureClassification::CACHE_PURGE,
			),
			true
		);
	}
}
