<?php

declare(strict_types=1);

namespace core\handler;

use ReflectionClass;
use utils\Command;
use utils\CommandInterface;
use utils\type\CommandType;

final class ProjectResultAsDtoHandler extends AbstractHandler
{
    private const REQUIRED_PARAMETERS_COUNT = 1;

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

        $payload = $command->getPayload();
        $instance = $payload[0];
        $responseArray = array_fill(0, $command->getPayloadSize() + 1, null);
        $responseArray[0] = $instance;

        $typeName = $this->getTypeName($instance);
        $responseArray[1] = new Command($command->getRuntimeName(), CommandType::GET_TYPE(), [$typeName]);

        $getInstanceFieldHandler = new GetInstanceFieldHandler();
        for ($i = 1; $i < $command->getPayloadSize(); $i++) {
            $propertyName = $payload[$i];
            $propertyValue = $getInstanceFieldHandler->process(
                new Command(
                    $command->getRuntimeName(),
                    CommandType::GET_INSTANCE_FIELD(),
                    [$instance, $propertyName]
                )
            );

            $responseArray[$i + 1] = new Command(
                $command->getRuntimeName(),
                CommandType::DTO_PROPERTY(),
                [$propertyName, $propertyValue]
            );
        }

        return $responseArray;
    }

    /**
     * @param mixed $instance
     */
    private function getTypeName($instance): string
    {
        if (!is_object($instance)) {
            return gettype($instance);
        }

        $reflection = new ReflectionClass($instance);
        $namespace = $reflection->getNamespaceName();
        $shortName = $reflection->getShortName();
        $typeName = $namespace !== '' ? $namespace . '.' . $shortName : $shortName;

        if ($typeName === '') {
            return $reflection->getName();
        }

        return ltrim($typeName, '.');
    }
}