<?php
/**
 * Copyright 2020 Adobe
 * All Rights Reserved.
 *
 * NOTICE: Adobe permits you to use, modify, and distribute this file in
 * accordance with the terms of the Adobe license agreement accompanying
 * it.
 */
declare(strict_types=1);

namespace Magento\Mray\CodeStructuralElement\Php\NodeRuntimeTypeResolver;

use PhpParser\Node\Expr;
use ReflectionClass;
use ReflectionException;
use TypeError;
use function array_map;
use function array_unique;
use function array_values;
use function sprintf;

class Rule
{
    /** @var string[] */
    private $exprClasses;
    /** @var Resolver  */
    private $resolver;

    /**
     * @param string[] $targetExpressions
     * @param Resolver $resolver
     */
    public function __construct(array $targetExpressions, Resolver $resolver)
    {
        $this->exprClasses = array_map(function (string $exprClass): string {
            try {
                $rc = new ReflectionClass($exprClass);
                if (!$rc->isSubclassOf(Expr::class)) {
                    throw new TypeError(sprintf('%s is not subtype of %s.', $exprClass, Expr::class));
                }
                if ($rc->isAbstract()) {
                    throw new TypeError(sprintf(
                        '%s is abstract. Runtime type resolution rule may be applied only to non-abstract class.',
                        $exprClass
                    ));
                }
                return $exprClass;
            } catch (ReflectionException $e) {
                throw new TypeError(sprintf('%s is unknown.', $exprClass), $e->getCode(), $e);
            }
        }, array_values(array_unique($targetExpressions)));
        $this->resolver = $resolver;
    }

    /**
     * @return string[]
     */
    public function getTargetExpressions(): array
    {
        return $this->exprClasses;
    }

    /**
     * @return Resolver
     */
    public function getResolver(): Resolver
    {
        return $this->resolver;
    }
}
