<?php

namespace AutoAdmin\Bundle\Content\Duplicator\Manager;

use AutoAdmin\Bundle\Admin\Factory\ContentFactory;
use AutoAdmin\Bundle\Content\Duplicator\Interfaces\DuplicatorInterface;
use Doctrine\Common\Util\ClassUtils;
use Symfony\Component\DependencyInjection\Attribute\TaggedIterator;

class DuplicatorManager
{
    public function __construct(
        /** @var DuplicatorInterface[] */
        #[TaggedIterator('aa_content.duplicator')]
        protected iterable $duplicators,
        protected ContentFactory $contentFactory,
    ) {
    }

    public function duplicate($entity): ?object
    {
        if ($entity == null) {
            return null;
        }

        $class = ClassUtils::getRealClass(get_class($entity));

        $duplicate = $this->contentFactory->createEntity($class);

        foreach ($this->duplicators as $duplicator) {
            if (!$duplicator->isSupported($entity)) {
                continue;
            }

            $duplicate = $duplicator->duplicate($entity, $duplicate);
        }

        $duplicate = $this->dumbDuplicate($entity, $duplicate);

        return $duplicate;
    }

    /**
     * Dumb data copy for builtin types (example: avoid nullable in a bool prop)
     *
     * @param object $entity
     * @param object $duplicate
     * @return object
     */
    protected function dumbDuplicate(object $entity, object $duplicate): object
    {
        $refl = new \ReflectionClass($entity);

        foreach ($refl->getProperties() as $property) {
            $propertyType = $property->getType();

            if (is_null($propertyType)) {
                continue;
            }

            $types = [];
            if ($propertyType instanceof \ReflectionNamedType) {
                $types = [$propertyType];
            } elseif ($propertyType instanceof \ReflectionUnionType || $propertyType instanceof \ReflectionIntersectionType) {
                $types = $propertyType->getTypes();
            }

            foreach ($types as $type) {
                if ($type?->isBuiltin()) {
                    switch ($type->getName()) {
                        case 'bool':
                            $currentVal = $property->getValue($duplicate);
                            if ($currentVal !== false && $currentVal !== true) {
                                $currentVal = $property->getValue($entity);
                                $property->setValue($duplicate, $currentVal);
                            }
                            break;
                        default:
                            // do nothing
                            break;
                    }
                }
            }
        }

        return $duplicate;
    }
}
