<?php
declare(strict_types=1);

namespace FiloBlu\Esb\Core\Expression;

use FiloBlu\Esb\Core\Exception\RuntimeException;
use FiloBlu\Esb\Core\Expression\Operator\OperatorInterface;
use Magento\Framework\DataObject;

/**
 * Class Expression
 * @package FiloBlu\Esb\Core\Expression
 */
class Expression implements ExpressionInterface
{
    /**
     * @var string
     */
    protected $field;

    /**
     * @var string
     */
    protected $operator;

    /**
     * @var string
     */
    protected $value;

    /**
     * @var array
     */
    private $operators;

    /**
     * @var VariableExpanderInterface
     */
    private $variableExpander;

    /**
     * Expression constructor.
     * @param VariableExpanderInterface $variableExpander
     * @param array[] $operators
     */
    public function __construct(VariableExpanderInterface $variableExpander, array $operators)
    {
        /** @var OperatorInterface $operator */
        foreach ($operators as $operator) {
            $this->operators[$operator->getSymbol()] = $operator;
        }
        $this->variableExpander = $variableExpander;
    }

    /**
     * @param DataObject $data
     * @return int
     */
    public function evaluate(DataObject $data): int
    {
        $leftValue = $this->variableExpander->expand($this->field, $data);
        $rightValue = $this->variableExpander->expand($this->value, $data);
        $symbol = $this->getOperator();

        if (!array_key_exists($symbol, $this->operators)) {
            throw new RuntimeException("Invalid operator provided {$symbol}");
        }

        /** @var OperatorInterface $operator */
        $operator = $this->operators[$symbol];
        return (int)$operator->execute($leftValue, $rightValue);
    }

//    /**
//     * @param $leftValue
//     * @param $rightValue
//     * @return int
//     */
//    public function operate($leftValue, $rightValue)
//    {
//
//        // TODO : must be configurable vi di.xml
//        //  switch ($this->getOperator()) {
//        //            case 'nin':
//        //                return !in_array($leftValue, is_array($rightValue) ? $rightValue : [$rightValue], false);
//        //            case 'in':
//        //                return in_array($leftValue, is_array($rightValue) ? $rightValue : [$rightValue], false);
//        //            case 'eq':
//        //                return $leftValue == $rightValue;
//        //            case 'seq':
//        //                return $leftValue === $rightValue;
//        //            case 'lt':
//        //               return $leftValue < $rightValue;
//        //           case 'lte':
//        //               return $leftValue <= $rightValue;
//        //          case 'gt':
//        //            return $leftValue > $rightValue;
//        //       case 'gte':
//        //         return $leftValue >= $rightValue;
//        //    case 'neq':
//        //      return $leftValue != $rightValue;
//        //   case 'startswith':
//        //  return $this->startsWith($leftValue, $rightValue);
//        //   case 'nstartswith':
//        //     return !$this->startsWith($leftValue, $rightValue);
//        //  case 'endswith':
//        //      return $this->endsWith($leftValue, $rightValue);
//        //  case 'nendswith':
//        //      return !$this->endsWith($leftValue, $rightValue);
//        // }
//    }

    /**
     * @return mixed
     */
    public function getOperator()
    {
        return $this->operator;
    }

    /**
     * @param $operator
     * @return $this
     */
    public function setOperator($operator): ExpressionInterface
    {
        $this->operator = $operator;
        return $this;
    }

    /**
     * @return mixed
     */
    public function getField()
    {
        return $this->field;
    }

    /**
     * @param $field
     * @return $this
     */
    public function setField($field): ExpressionInterface
    {
        $this->field = $field;
        return $this;
    }

    /**
     * @return mixed
     */
    public function getValue()
    {
        return $this->value;
    }

    /**
     * @param $value
     * @return $this
     */
    public function setValue($value): ExpressionInterface
    {
        $this->value = $value;
        return $this;
    }

//    /**
//     * @param $haystack
//     * @param $needle
//     * @return bool
//     */
//    public function startsWith($haystack, $needle)
//    {
//        $length = strlen($needle);
//        return (substr($haystack, 0, $length) === $needle);
//    }
//
//    /**
//     * @param $haystack
//     * @param $needle
//     * @return bool
//     */
//    public function endsWith($haystack, $needle)
//    {
//        $length = strlen($needle);
//        if ($length == 0) {
//            return true;
//        }
//        return (substr($haystack, -$length) === $needle);
//    }
}
