<?php

declare(strict_types=1);

namespace ComerciaGlobalPayments\AddonPayments\SDK\Encryption\Cypher;

use RuntimeException;

/**
 * Trait IvGeneratorTrait.
 *
 * Provides secure initialization vector value.
 */
trait IvGeneratorTrait
{
    /**
     * Generates an initialization vector.
     *
     * @SuppressWarnings(PHPMD.BooleanArgumentFlag)
     */
    public function generateIv(bool $allowLessSecureIv = false): string
    {
        $success = false;
        $ivLength = openssl_cipher_iv_length(static::NAME);
        $random = openssl_random_pseudo_bytes($ivLength, $success);
        if (!$success || !$random) {
            try {
                $random = random_bytes(static::IV_LENGTH);
            } catch (\Exception $e) {
                if (!$allowLessSecureIv) {
                    throw new RuntimeException('Unable to generate initialization vector (IV)');
                }

                $random = $this->generateInsecureIv(static::IV_LENGTH);
            }
        }

        return $random;
    }

    /**
     * Generates a random string to be used as an initialization vector if all other methods fail.
     *
     * Not recommended for production use.
     */
    public function generateInsecureIv(int $length): string
    {
        $permitted_chars = implode(
            '',
            array_merge( // @codeCoverageIgnore
                range('A', 'z'),
                range(0, 9),
                str_split('~!@#$%&*()-=+{};:"<>,.?/\'')
            )
        );
        try {
            $random = '';
            for ($i = 0; $i < $length; ++$i) {
                $random .= $permitted_chars[random_int(0, $length - 1)];
            }

            return $random;
        } catch (\Exception $e) {
            throw new RuntimeException('Unable to generate insecure initialization vector (IV)');
        }
    }
}
