<?php

declare (strict_types=1);
namespace ProfilePressVendor\Sabberworm\CSS\Value;

use ProfilePressVendor\Sabberworm\CSS\Parsing\ParserState;
use ProfilePressVendor\Sabberworm\CSS\Parsing\UnexpectedEOFException;
use ProfilePressVendor\Sabberworm\CSS\Parsing\UnexpectedTokenException;
use function ProfilePressVendor\Safe\preg_match;
class CalcFunction extends CSSFunction
{
    private const T_OPERAND = 1;
    private const T_OPERATOR = 2;
    /**
     * @throws UnexpectedTokenException
     * @throws UnexpectedEOFException
     *
     * @internal since V8.8.0
     */
    public static function parse(ParserState $parserState, bool $ignoreCase = \false): CSSFunction
    {
        $operators = ['+', '-', '*', '/'];
        $function = $parserState->parseIdentifier();
        if ($parserState->peek() !== '(') {
            // Found ; or end of line before an opening bracket
            throw new UnexpectedTokenException('(', $parserState->peek(), 'literal', $parserState->currentLine());
        } elseif ($function !== 'calc') {
            // Found invalid calc definition. Example calc (...
            throw new UnexpectedTokenException('calc', $function, 'literal', $parserState->currentLine());
        }
        $parserState->consume('(');
        $calcRuleValueList = new CalcRuleValueList($parserState->currentLine());
        $list = new RuleValueList(',', $parserState->currentLine());
        $nestingLevel = 0;
        $lastComponentType = null;
        while (!$parserState->comes(')') || $nestingLevel > 0) {
            if ($parserState->isEnd() && $nestingLevel === 0) {
                break;
            }
            $parserState->consumeWhiteSpace();
            if ($parserState->comes('(')) {
                $nestingLevel++;
                $calcRuleValueList->addListComponent($parserState->consume(1));
                $parserState->consumeWhiteSpace();
                continue;
            } elseif ($parserState->comes(')')) {
                $nestingLevel--;
                $calcRuleValueList->addListComponent($parserState->consume(1));
                $parserState->consumeWhiteSpace();
                continue;
            }
            if ($lastComponentType !== CalcFunction::T_OPERAND) {
                $value = Value::parsePrimitiveValue($parserState);
                $calcRuleValueList->addListComponent($value);
                $lastComponentType = CalcFunction::T_OPERAND;
            } else if (\in_array($parserState->peek(), $operators, \true)) {
                if ($parserState->comes('-') || $parserState->comes('+')) {
                    if (preg_match('/\s/', $parserState->peek(1, -1)) !== 1 || preg_match('/\s/', $parserState->peek(1, 1)) !== 1) {
                        throw new UnexpectedTokenException(" {$parserState->peek()} ", $parserState->peek(1, -1) . $parserState->peek(2), 'literal', $parserState->currentLine());
                    }
                }
                $calcRuleValueList->addListComponent($parserState->consume(1));
                $lastComponentType = CalcFunction::T_OPERATOR;
            } else {
                throw new UnexpectedTokenException(\sprintf('Next token was expected to be an operand of type %s. Instead "%s" was found.', \implode(', ', $operators), $parserState->peek()), '', 'custom', $parserState->currentLine());
            }
            $parserState->consumeWhiteSpace();
        }
        $list->addListComponent($calcRuleValueList);
        if (!$parserState->isEnd()) {
            $parserState->consume(')');
        }
        return new CalcFunction($function, $list, ',', $parserState->currentLine());
    }
    /**
     * @return array<string, bool|int|float|string|array<mixed>|null>
     *
     * @internal
     */
    public function getArrayRepresentation(): array
    {
        throw new \BadMethodCallException('`getArrayRepresentation` is not yet implemented for `' . self::class . '`');
    }
}
