<?php

namespace FiloBlu\Esb\Core\Expression;

use Magento\Framework\DataObject;
use RuntimeException;

/**
 * Class SwitchExpressionEvaluator
 * @package FiloBlu\Esb\Core\Expression
 */
class SwitchExpressionEvaluator
{
    /**
     * @var EvaluatorInterfaceFactory
     */
    private $evaluatorFactory;
    /**
     * @var VariableExpanderInterface
     */
    private $variableExpander;

    /**
     * SwitchExpressionEvaluator constructor.
     * @param EvaluatorInterfaceFactory $evaluatorFactory
     * @param VariableExpanderInterface $variableExpander
     */
    public function __construct(EvaluatorInterfaceFactory $evaluatorFactory, VariableExpanderInterface $variableExpander)
    {
        $this->evaluatorFactory = $evaluatorFactory;
        $this->variableExpander = $variableExpander;
    }

    /**
     * @param $value
     * @return bool
     */
    public function is($value): bool
    {
        if (\is_object($value)) {
            if (!property_exists($value, 'when')) {
                return false;
            }

            if (!property_exists($value, 'default')) {
                return false;
            }
            return true;
        }

        if (\is_array($value)) {
            return \array_key_exists('when', $value) && \array_key_exists('default', $value);
        }

        return false;
    }

    /**
     * @param $expression
     * @param DataObject $data
     * @return mixed
     * @throws RuntimeException
     */
    public function evaluate($expression, DataObject $data)
    {
        if (\is_object($expression)) {
            $result = $expression->default;
            $when = $expression->when;
        } elseif (\is_array($expression)) {
            $result = $expression['default'];
            $when = $expression['when'];
        } else {
            throw new RuntimeException(__('Invalid switch expression. must be an array or object'));
        }

        $evaluator = $this->evaluatorFactory->create();
        foreach ($when as $statement) {

            if (\is_object($statement)) {
                $conditions = $statement->condition;
            } elseif (\is_array($expression)) {
                $conditions = $statement['condition'];
            } else {
                throw new RuntimeException(__('Invalid switch expression. must be an array or object'));
            }

            if ($evaluator->reset()->compile($conditions)->evaluate($data)) {

                if (\is_object($statement)) {
                    return $this->variableExpander->expand($statement->return, $data);
                }

                if (\is_array($statement)) {
                    return $this->variableExpander->expand($statement['return'], $data);
                }

                throw new RuntimeException(__('Invalid statement expression. must be an array or object'));
            }
        }

        return $this->variableExpander->expand($result, $data);
    }

    /**
     * @return \FiloBlu\Esb\Core\Expression\VariableExpanderInterface
     */
    public function getVariableExpander(): VariableExpanderInterface
    {
        return $this->variableExpander;
    }
}
