<?php
/**
 * HTTP Status Codes
 *
 * Centralized HTTP status code definitions and helper methods for consistent
 * handling of retryable errors, rate limits, and authentication failures.
 *
 * @package Sequensy
 * @since 2.0.0
 */

declare(strict_types=1);

namespace Sequensy\Http;

// If this file is called directly, abort.
if ( ! defined( 'WPINC' ) ) {
	die;
}

/**
 * Class HttpStatusCodes
 *
 * Provides centralized HTTP status code classification for API integrations.
 */
final class HttpStatusCodes {

	/**
	 * HTTP status codes that indicate retryable errors.
	 *
	 * These are transient failures that may succeed on retry.
	 *
	 * @var array<int>
	 */
	public const RETRYABLE = array(
		408, // Request Timeout
		429, // Too Many Requests (rate limit)
		500, // Internal Server Error
		502, // Bad Gateway
		503, // Service Unavailable
		504, // Gateway Timeout
	);

	/**
	 * HTTP status codes that indicate rate limiting.
	 *
	 * @var array<int>
	 */
	public const RATE_LIMITED = array(
		429, // Too Many Requests
	);

	/**
	 * HTTP status codes that indicate authentication failures.
	 *
	 * These typically require user intervention (invalid credentials, revoked access).
	 *
	 * @var array<int>
	 */
	public const AUTH_FAILED = array(
		401, // Unauthorized
		403, // Forbidden
	);

	/**
	 * HTTP status codes that indicate client errors.
	 *
	 * @var array<int>
	 */
	public const CLIENT_ERROR_RANGE = array( 400, 499 );

	/**
	 * HTTP status codes that indicate server errors.
	 *
	 * @var array<int>
	 */
	public const SERVER_ERROR_RANGE = array( 500, 599 );

	/**
	 * Check if a status code is retryable.
	 *
	 * @param int|null $code HTTP status code.
	 * @return bool True if the status code indicates a retryable error.
	 */
	public static function isRetryable( ?int $code ): bool {
		// No status code usually means network error - retryable.
		if ( null === $code ) {
			return true;
		}

		return in_array( $code, self::RETRYABLE, true );
	}

	/**
	 * Check if a status code indicates rate limiting.
	 *
	 * @param int|null $code HTTP status code.
	 * @return bool True if the status code indicates rate limiting.
	 */
	public static function isRateLimited( ?int $code ): bool {
		if ( null === $code ) {
			return false;
		}

		return in_array( $code, self::RATE_LIMITED, true );
	}

	/**
	 * Check if a status code indicates an authentication error.
	 *
	 * @param int|null $code HTTP status code.
	 * @return bool True if the status code indicates an auth error.
	 */
	public static function isAuthError( ?int $code ): bool {
		if ( null === $code ) {
			return false;
		}

		return in_array( $code, self::AUTH_FAILED, true );
	}

	/**
	 * Check if a status code is a client error (4xx).
	 *
	 * @param int|null $code HTTP status code.
	 * @return bool True if the status code is in the 4xx range.
	 */
	public static function isClientError( ?int $code ): bool {
		if ( null === $code ) {
			return false;
		}

		return $code >= self::CLIENT_ERROR_RANGE[0] && $code <= self::CLIENT_ERROR_RANGE[1];
	}

	/**
	 * Check if a status code is a server error (5xx).
	 *
	 * @param int|null $code HTTP status code.
	 * @return bool True if the status code is in the 5xx range.
	 */
	public static function isServerError( ?int $code ): bool {
		if ( null === $code ) {
			return false;
		}

		return $code >= self::SERVER_ERROR_RANGE[0] && $code <= self::SERVER_ERROR_RANGE[1];
	}

	/**
	 * Check if a status code indicates success (2xx).
	 *
	 * @param int|null $code HTTP status code.
	 * @return bool True if the status code is in the 2xx range.
	 */
	public static function isSuccess( ?int $code ): bool {
		if ( null === $code ) {
			return false;
		}

		return $code >= 200 && $code <= 299;
	}

	/**
	 * Get human-readable description for a status code.
	 *
	 * @param int $code HTTP status code.
	 * @return string Status description.
	 */
	public static function getDescription( int $code ): string {
		$descriptions = array(
			200 => 'OK',
			201 => 'Created',
			204 => 'No Content',
			400 => 'Bad Request',
			401 => 'Unauthorized',
			403 => 'Forbidden',
			404 => 'Not Found',
			408 => 'Request Timeout',
			429 => 'Too Many Requests',
			500 => 'Internal Server Error',
			502 => 'Bad Gateway',
			503 => 'Service Unavailable',
			504 => 'Gateway Timeout',
		);

		return $descriptions[ $code ] ?? 'Unknown Status';
	}
}
