<?php

namespace Application\Service\Extension\Helper\components;

use Application\Service\Extension\Expression\ExpressionLanguage;
use Application\Service\Extension\Helper\base\BaseHelper;
use Application\Service\Extension\Helper\StringHelper;
use Symfony\Component\ExpressionLanguage\ExpressionFunction;

class ExpressionHelper extends BaseHelper
{
    private ?string $expression = null;
    private array $values = [];

    private ?ExpressionLanguage $exInstance = null;

    private $executeValue = null;

    private $executeComplie = null;

    public function __construct($config = [])
    {
        parent::__construct($config);
        $this->exInstance = new ExpressionLanguage();
        $this->exInstance->register('IF', function ($con, $trueRes, $falseRes) {
            return "{$con} ? {$trueRes} : {$falseRes}";
        }, function ($argument, $str, $trueRes, $falseRes) {
            return $str ? $trueRes : $falseRes;
        });

        $this->exInstance->register('AND', function (...$con) {
            return implode(' && ', $con);
        }, function ($argument, ...$str) {
            return !in_array(false, $str);
        });

        $this->exInstance->register('OR', function (...$con) {
            return implode(' || ', $con);
        }, function ($argument, ...$str) {
            return in_array(true, $str);
        });

        // 将数字保留几位小数
        $this->exInstance->register('ROUNDTO', function (...$con) {
            return 'ROUNDTO' . '(' . implode(',', $con) . ')';
        }, function ($argument, $value, $decimalPoint) {
            return StringHelper::stringToFloat($value, $decimalPoint);
        });

        $this->exInstance->register('DATEDIF', function (...$con) {
            return 'DATEDIF' . '(' . implode(',', $con) . ')';
        }, function ($argument, $start_date, $end_date, $unit) {
            $startDateTime = new \DateTime(is_numeric($start_date) ? date('Y-m-d', $start_date) : $start_date);
            $endDateTime = new \DateTime(is_numeric($end_date) ? date('Y-m-d', $end_date) : $end_date);

            // 计算日期差异
            $diff = $startDateTime->diff($endDateTime, true);
            switch ($unit) {
                case 'Y':
                    return floor($diff->days / 365); // 相差时间以年为单位
                case 'M':
                    return $diff->y * 12 + $diff->m; // 相差时间以月为单位
                case 'D':
                    return $diff->days; // 相差时间以日为单位
                case 'H':
                    return $diff->days * 24 + $diff->h; // 相差日期以小时为单位
                case 'I':
                    return $diff->days * 24 * 60 + $diff->h * 60 + $diff->i; // 相差日期以分钟为单位
                case 'S':
                    return $diff->days * 24 * 60 * 60 + $diff->h * 60 * 60 + $diff->i * 60 + $diff->s;
                default:
                    return false; // 未知的单位
            }
        });

        $round = ExpressionFunction::fromPhp('round', 'ROUND');
        $floor = ExpressionFunction::fromPhp('floor', 'FLOOR');
        $log = ExpressionFunction::fromPhp('log', 'LN');
        $time = ExpressionFunction::fromPhp('time', 'NOW');
        $this->exInstance->addFunction($round);
        $this->exInstance->addFunction($log);
        $this->exInstance->addFunction($time);
        $this->exInstance->addFunction($floor);
    }

    protected function setCache($value, string $helperKey = self::HELPER_KEY_BASE)
    {
        // TODO: Implement setCache() method.
    }

    protected function getCacheKey()
    {
        // TODO: Implement getCacheKey() method.
    }

    public function setExpression(string $expressionLanguage)
    {
        $this->expression = $expressionLanguage;
        return $this;
    }

    public function setValues(array $values)
    {
        $this->values = $values;
        return $this;
    }

    public function execute(): ExpressionHelper
    {
        try {
            $this->executeValue = $this->exInstance->evaluate($this->expression, $this->values);
            $this->executeComplie = $this->exInstance->compile($this->expression ,$this->values);
        } catch (\Throwable $throwable) {
            $this->executeValue = '';
            $this->executeComplie = $throwable->getMessage();
//            throw new \Exception('公式计算失败。请核对公式是否正确');
        }

        return $this;
    }

    public function getExecuteVal()
    {
        return $this->executeValue;
    }

    public function getExecuteCompile()
    {
        return $this->executeComplie;
    }

    public static function handleExpression(string $expression): string
    {
        $val = explode('=', $expression);
        unset($val[0]);
        return trim(implode('=', $val));
    }
}