<?php

declare(strict_types=1);

namespace core\handler;

use ReflectionClass;
use ReflectionException;
use Exception;
use utils\CommandInterface;
use utils\exception\FieldNotFoundInClassException;

final class SetStaticFieldHandler extends AbstractHandler
{
    private const REQUIRED_ARGUMENTS_COUNT = 3;

    public function process(CommandInterface $command): object
    {
        $this->validate($command, self::REQUIRED_ARGUMENTS_COUNT, self::class);

        $typee = $command->getPayloadByIndex(0);
        $fieldName = (string) $command->getPayloadByIndex(1);
        $newValue = $command->getPayloadByIndex(2);

        try {
            $reflectionClass = $this->getReflectionClass($typee);
            if (!$reflectionClass->hasProperty($fieldName)) {
                throw new ReflectionException(sprintf('Property %s not found', $fieldName));
            }

            $property = $reflectionClass->getProperty($fieldName);
            if (!$property->isStatic()) {
                throw new Exception(sprintf('Property %s is not static', $fieldName));
            }

            $property->setAccessible(true);
            $property->setValue(null, $newValue);
        } catch (ReflectionException $e) {
            throw new FieldNotFoundInClassException($fieldName, $typee);
        }

        return $typee;
    }

    /**
     * @param mixed $typee
     */
    private function getReflectionClass($typee): ReflectionClass
    {
        if ($typee instanceof ReflectionClass) {
            return $typee;
        }

        return new ReflectionClass($typee);
    }
}
