<?php
/*
 * @package   stats_collector
 * @copyright Copyright (c)2023-2024 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\UsageStats\Collector\Random;

use Akeeba\UsageStats\Collector\Random\Adapter\AdapterInterface;
use Akeeba\UsageStats\Collector\Random\Adapter\CompatibilityAdapter;
use Akeeba\UsageStats\Collector\Random\Adapter\OpenSSLAdapter;
use Akeeba\UsageStats\Collector\Random\Adapter\RandomBytesAdapter;

/**
 * Random Data Generator abstraction
 *
 * @since  1.0.0
 */
final class Random
{
	private const ADAPTERS = [
		RandomBytesAdapter::class,
		OpenSSLAdapter::class,
		CompatibilityAdapter::class,
	];

	/**
	 * The adapter for generating random bytes
	 *
	 * @var   AdapterInterface|null
	 * @since 1.0.0
	 */
	private $adapter = null;

	/**
	 * Returns a number of bytes using a cryptographically secure pseudorandom number generator (CS-PRNG).
	 *
	 * @param   int  $length  How many bytes to retrieve
	 *
	 * @return  string  The randomly generated bytes
	 * @since   1.0.0
	 */
	public function getRandomBytes(int $length = 120): string
	{
		return $this->getAdapter()->getRandomBytes(120);
	}

	/**
	 * Get the appropriate adapter for generating random bytes
	 *
	 * @return  AdapterInterface|null
	 * @since   1.0.0
	 */
	private function getAdapter(): ?AdapterInterface
	{
		if ($this->adapter !== null)
		{
			return $this->adapter;
		}

		foreach (self::ADAPTERS as $className)
		{
			if (!class_exists($className))
			{
				continue;
			}

			/** @var AdapterInterface $o */
			$o = new $className;

			if (!$o->isAvailable())
			{
				continue;
			}

			return $this->adapter = $o;
		}

		return null;
	}

}