<?php
/**
 * Provider cooldown manager for chatbot requests.
 *
 * @package AIPT\Api\Chatbot
 * @since 2.5.0
 */

namespace AIPT\Api\Chatbot;

/**
 * ProviderCooldown class
 *
 * Manages cooldown periods when AI provider returns 429/5xx errors.
 * Uses WordPress transients to track cooldown state globally.
 */
class ProviderCooldown {

	/**
	 * Transient key for cooldown state.
	 */
	private const TRANSIENT_KEY = 'aipt_provider_cooldown';

	/**
	 * Settings instance.
	 *
	 * @var ChatbotSettings
	 */
	private ChatbotSettings $settings;

	/**
	 * Constructor.
	 *
	 * @param ChatbotSettings|null $settings Settings instance.
	 */
	public function __construct( ?ChatbotSettings $settings = null ) {
		$this->settings = $settings ?? new ChatbotSettings();
	}

	/**
	 * Check if cooldown is currently active.
	 *
	 * Performance note: We calculate retry_after from the stored expiry timestamp
	 * instead of querying the database for transient TTL. This avoids an extra
	 * DB query on every check.
	 *
	 * @return array{active: bool, retry_after: int} Cooldown status.
	 */
	public function isActive(): array {
		if ( ! $this->isEnabled() ) {
			return [ 'active' => false, 'retry_after' => 0 ];
		}

		$expiry = get_transient( self::TRANSIENT_KEY );

		if ( false === $expiry ) {
			return [ 'active' => false, 'retry_after' => 0 ];
		}

		$retry_after = (int) $expiry - time();

		if ( $retry_after <= 0 ) {
			return [ 'active' => false, 'retry_after' => 0 ];
		}

		return [
			'active'      => true,
			'retry_after' => $retry_after,
		];
	}

	/**
	 * Minimum cooldown duration in seconds.
	 * Prevents set_transient() from creating never-expiring transients.
	 */
	private const MIN_COOLDOWN_SECONDS = 1;

	/**
	 * Activate cooldown period.
	 *
	 * Called when provider returns 429 or 5xx error.
	 *
	 * @return bool True if cooldown was activated.
	 */
	public function activate(): bool {
		if ( ! $this->isEnabled() ) {
			return false;
		}

		$seconds = $this->getCooldownSeconds();

		if ( $seconds < self::MIN_COOLDOWN_SECONDS ) {
			$seconds = self::MIN_COOLDOWN_SECONDS;
		}

		$expiry = time() + $seconds;

		return set_transient( self::TRANSIENT_KEY, $expiry, $seconds );
	}

	/**
	 * Clear the cooldown (for admin/testing purposes).
	 *
	 * @return bool True if transient was deleted.
	 */
	public function clear(): bool {
		return delete_transient( self::TRANSIENT_KEY );
	}

	/**
	 * Check if provider cooldown is enabled.
	 *
	 * @return bool True if enabled.
	 */
	public function isEnabled(): bool {
		return (bool) $this->settings->get( 'provider_cooldown.enabled', true );
	}

	/**
	 * Get cooldown duration in seconds.
	 *
	 * @return int Cooldown seconds.
	 */
	public function getCooldownSeconds(): int {
		return (int) $this->settings->get( 'provider_cooldown.seconds', 60 );
	}

	/**
	 * Check if messages should be enqueued when cooldown activates.
	 *
	 * @return bool True if messages should be enqueued.
	 */
	public function shouldEnqueueOnFailure(): bool {
		return (bool) $this->settings->get( 'provider_cooldown.enqueue_on_failure', false );
	}
}
