<?php

namespace App\Rules;

use Closure;
use Illuminate\Contracts\Validation\ValidationRule;
use Illuminate\Translation\PotentiallyTranslatedString;
use ReflectionFunction;

class GeneratorFunctionExists implements ValidationRule {
    /**
     * Run the validation rule.
     *
     * @param string $attribute
     * @param mixed $value
     * @param Closure(string): PotentiallyTranslatedString $fail
     */
    public function validate( string $attribute, mixed $value, Closure $fail ): void {
        if ( ! function_exists( $value ) ) {
            $fail( __( 'Function name must be a PHP function.' ) );
        } elseif ( function_exists( $value ) ) {
            $reflection = new ReflectionFunction( $value );

            if ( ! $reflection->isUserDefined() ) {
                $fail( __( 'The PHP function must be user defined.' ) );
            } else if ( ! str_contains( $reflection->getFileName(), 'CustomGeneratorFunctions.php' ) ) {
                $fail( __( 'The PHP function must be located in the file CustomGeneratorFunctions.php.' ) );
            } else if ( call_user_func( $value ) == '' ) {
                $fail( __( 'The PHP function must return a string 1 character or longer.' ) );
            } else {
                $values = array_map( function ( $i ) use ( $value ) {
                    return call_user_func( $value );
                }, range( 0, 99 ) );

                $unique = array_unique( $values );
                sort( $values );
                sort( $unique );

                if ( $values != $unique ) {
                    $fail( __( 'The PHP function must return a different value every time it is called.' ) );
                }
            }
        }
    }
}
