<?php

namespace LWVendor\PhpOffice\PhpSpreadsheet\Style\ConditionalFormatting\Wizard;

use LWVendor\PhpOffice\PhpSpreadsheet\Calculation\Calculation;
use LWVendor\PhpOffice\PhpSpreadsheet\Exception;
use LWVendor\PhpOffice\PhpSpreadsheet\Style\Conditional;
use LWVendor\PhpOffice\PhpSpreadsheet\Style\ConditionalFormatting\Wizard;
/**
 * @method TextValue contains(string $value, string $operandValueType = Wizard::VALUE_TYPE_LITERAL)
 * @method TextValue doesNotContain(string $value, string $operandValueType = Wizard::VALUE_TYPE_LITERAL)
 * @method TextValue doesntContain(string $value, string $operandValueType = Wizard::VALUE_TYPE_LITERAL)
 * @method TextValue beginsWith(string $value, string $operandValueType = Wizard::VALUE_TYPE_LITERAL)
 * @method TextValue startsWith(string $value, string $operandValueType = Wizard::VALUE_TYPE_LITERAL)
 * @method TextValue endsWith(string $value, string $operandValueType = Wizard::VALUE_TYPE_LITERAL)
 */
class TextValue extends WizardAbstract implements WizardInterface
{
    protected const MAGIC_OPERATIONS = ['contains' => Conditional::OPERATOR_CONTAINSTEXT, 'doesntContain' => Conditional::OPERATOR_NOTCONTAINS, 'doesNotContain' => Conditional::OPERATOR_NOTCONTAINS, 'beginsWith' => Conditional::OPERATOR_BEGINSWITH, 'startsWith' => Conditional::OPERATOR_BEGINSWITH, 'endsWith' => Conditional::OPERATOR_ENDSWITH];
    protected const OPERATORS = [Conditional::OPERATOR_CONTAINSTEXT => Conditional::CONDITION_CONTAINSTEXT, Conditional::OPERATOR_NOTCONTAINS => Conditional::CONDITION_NOTCONTAINSTEXT, Conditional::OPERATOR_BEGINSWITH => Conditional::CONDITION_BEGINSWITH, Conditional::OPERATOR_ENDSWITH => Conditional::CONDITION_ENDSWITH];
    protected const EXPRESSIONS = [Conditional::OPERATOR_CONTAINSTEXT => 'NOT(ISERROR(SEARCH(%s,%s)))', Conditional::OPERATOR_NOTCONTAINS => 'ISERROR(SEARCH(%s,%s))', Conditional::OPERATOR_BEGINSWITH => 'LEFT(%s,LEN(%s))=%s', Conditional::OPERATOR_ENDSWITH => 'RIGHT(%s,LEN(%s))=%s'];
    /** @var string */
    protected $operator;
    /** @var string */
    protected $operand;
    /**
     * @var string
     */
    protected $operandValueType;
    public function __construct(string $cellRange)
    {
        parent::__construct($cellRange);
    }
    protected function operator(string $operator) : void
    {
        if (!isset(self::OPERATORS[$operator])) {
            throw new Exception('Invalid Operator for Text Value CF Rule Wizard');
        }
        $this->operator = $operator;
    }
    protected function operand(string $operand, string $operandValueType = Wizard::VALUE_TYPE_LITERAL) : void
    {
        $operand = $this->validateOperand($operand, $operandValueType);
        $this->operand = $operand;
        $this->operandValueType = $operandValueType;
    }
    protected function wrapValue(string $value) : string
    {
        return '"' . $value . '"';
    }
    protected function setExpression() : void
    {
        $operand = $this->operandValueType === Wizard::VALUE_TYPE_LITERAL ? $this->wrapValue(\str_replace('"', '""', $this->operand)) : $this->cellConditionCheck($this->operand);
        if ($this->operator === Conditional::OPERATOR_CONTAINSTEXT || $this->operator === Conditional::OPERATOR_NOTCONTAINS) {
            $this->expression = \sprintf(self::EXPRESSIONS[$this->operator], $operand, $this->referenceCell);
        } else {
            $this->expression = \sprintf(self::EXPRESSIONS[$this->operator], $this->referenceCell, $operand, $operand);
        }
    }
    public function getConditional() : Conditional
    {
        $this->setExpression();
        $conditional = new Conditional();
        $conditional->setConditionType(self::OPERATORS[$this->operator]);
        $conditional->setOperatorType($this->operator);
        $conditional->setText($this->operandValueType !== Wizard::VALUE_TYPE_LITERAL ? $this->cellConditionCheck($this->operand) : $this->operand);
        $conditional->setConditions([$this->expression]);
        $conditional->setStyle($this->getStyle());
        $conditional->setStopIfTrue($this->getStopIfTrue());
        return $conditional;
    }
    public static function fromConditional(Conditional $conditional, string $cellRange = 'A1') : WizardInterface
    {
        if (!\in_array($conditional->getConditionType(), self::OPERATORS, \true)) {
            throw new Exception('Conditional is not a Text Value CF Rule conditional');
        }
        $wizard = new self($cellRange);
        $wizard->operator = (string) \array_search($conditional->getConditionType(), self::OPERATORS, \true);
        $wizard->style = $conditional->getStyle();
        $wizard->stopIfTrue = $conditional->getStopIfTrue();
        // Best-guess to try and identify if the text is a string literal, a cell reference or a formula?
        $wizard->operandValueType = Wizard::VALUE_TYPE_LITERAL;
        $condition = $conditional->getText();
        if (\preg_match('/^' . Calculation::CALCULATION_REGEXP_CELLREF_RELATIVE . '$/i', $condition)) {
            $wizard->operandValueType = Wizard::VALUE_TYPE_CELL;
            $condition = self::reverseAdjustCellRef($condition, $cellRange);
        } elseif (\preg_match('/\\(\\)/', $condition) || \preg_match('/' . Calculation::CALCULATION_REGEXP_CELLREF_RELATIVE . '/i', $condition)) {
            $wizard->operandValueType = Wizard::VALUE_TYPE_FORMULA;
        }
        $wizard->operand = $condition;
        return $wizard;
    }
    /**
     * @param string $methodName
     * @param mixed[] $arguments
     */
    public function __call($methodName, $arguments) : self
    {
        if (!isset(self::MAGIC_OPERATIONS[$methodName])) {
            throw new Exception('Invalid Operation for Text Value CF Rule Wizard');
        }
        $this->operator(self::MAGIC_OPERATIONS[$methodName]);
        //$this->operand(...$arguments);
        if (\count($arguments) < 2) {
            $this->operand($arguments[0]);
        } else {
            $this->operand($arguments[0], $arguments[1]);
        }
        return $this;
    }
}
