<?php

namespace Drupal\acquia_contenthub\Libs\PullSyndication;

use Drupal\acquia_contenthub\Exception\QueueItemInputViolationException;

/**
 * Provides validation constants and function for Content Hub pull syndication.
 *
 * @internal
 * @package Drupal\acquia_contenthub\Libs\PullSyndication
 */
final class QueueItemInputValidator {

  /**
   * The maximum number of items to be fetched from CH service.
   */
  public const RECEIVE_QUEUE_ITEMS_MAX_LIMIT = 100;

  /**
   * The minimum number of items to be fetched from CH service.
   */
  public const RECEIVE_QUEUE_ITEMS_MIN_LIMIT = 1;

  /**
   * Maximum visibility_timeout for items in service queue in seconds.
   *
   * 14 days = 1,209,600 seconds.
   */
  public const MAX_VISIBILITY_TIMEOUT = 1209600;

  /**
   * Acceptable units for visibility_timeout.
   */
  public const VALID_VISIBILITY_TIMEOUT_UNITS = 'ns, us, µs, ms, s, m, h';

  /**
   * Validates visibility timeout value.
   *
   * Acceptable units are: ns, us, µs, ms, s, m, h (e.g., 300s, 5m, 1h).
   *
   * @param string $visibility_timeout
   *   The visibility timeout value to validate.
   *
   * @throws \Drupal\acquia_contenthub\Exception\QueueItemInputViolationException
   *   Thrown when the input violates the constraints.
   */
  public static function validateVisibilityTimeout(string $visibility_timeout): void {
    if (!preg_match('/^(\d+)(ns|us|µs|ms|s|m|h)$/', $visibility_timeout, $matches)) {
      throw new QueueItemInputViolationException('Invalid visibility timeout format. Must be suffixed with duration unit. E.g. 3600s, 60m, 1h. Valid units : ' . self::VALID_VISIBILITY_TIMEOUT_UNITS);
    }

    $value = (int) $matches[1];
    $unit = $matches[2];
    $seconds = 0;

    // Convert everything to seconds for comparison.
    switch ($unit) {
      case 'ns':
        $seconds = $value / 1000000000;
        break;

      case 'us':
      case 'µs':
        $seconds = $value / 1000000;
        break;

      case 'ms':
        $seconds = $value / 1000;
        break;

      case 's':
        $seconds = $value;
        break;

      case 'm':
        $seconds = $value * 60;
        break;

      case 'h':
        $seconds = $value * 3600;
        break;
    }

    if ($seconds > self::MAX_VISIBILITY_TIMEOUT) {
      throw new QueueItemInputViolationException('Visibility timeout cannot exceed 336h.');
    }
  }

  /**
   * Checks if limit value is within range.
   *
   * @param int $limit
   *   Limit value to validate.
   *
   * @return bool
   *   Returns TRUE if limit is in range, otherwise FALSE.
   */
  public static function isWithinSyndicationLimit(int $limit): bool {
    return $limit <= self::RECEIVE_QUEUE_ITEMS_MAX_LIMIT && $limit >= self::RECEIVE_QUEUE_ITEMS_MIN_LIMIT;
  }

}
