<?php

namespace AutoAdmin\Bundle\BrickBuilder\Builder;

use AutoAdmin\Bundle\BrickBuilder\Brick\BrickHandlerManagerInterface;
use AutoAdmin\Bundle\BrickBuilder\Brick\ConfigSetting\EntityCollectionSetting;
use AutoAdmin\Bundle\BrickBuilder\Brick\ConfigSetting\EntitySetting;
use AutoAdmin\Bundle\BrickBuilder\Brick\ConfigSetting\ScalarCollectionSetting;
use AutoAdmin\Bundle\BrickBuilder\Brick\ConfigSetting\ScalarSetting;
use AutoAdmin\Bundle\BrickBuilder\Brick\ConfigSetting\SubEntityCollectionSetting;
use AutoAdmin\Bundle\BrickBuilder\Entity\Brick;
use AutoAdmin\Bundle\BrickBuilder\Helper\DatabaseBrickFormat;
use AutoAdmin\Bundle\BrickBuilder\Model\BrickInterface;
use AutoAdmin\Bundle\Content\Service\DuplicatorService;
use AutoAdmin\Bundle\Media\Form\Type\ImageType;
use AutoAdmin\Bundle\Media\Model\AbstractImage;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\FormType;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;

class BuilderService
{
    public function __construct(
        protected FormFactoryInterface $factory,
        protected DuplicatorService $duplicatorService,
        protected EntityManagerInterface $em,
        protected BrickHandlerManagerInterface $handlerManager,
        protected DatabaseBrickFormat $brickFormat,
        protected PropertyAccessorInterface $accessor,
    )
    {
    }

    public function createRoot(): BrickInterface
    {
        return (new Brick())->setType('brick.root');
    }

    public function getRoot(object $entity, string $property, bool $create = false)
    {
        $root = $this->accessor->getValue($entity, $property);
        if ($root === null && $create === true) {
            $root = $this->createRoot();
        }

        return $root;
    }

    public function buildForm($subject = null): FormBuilderInterface
    {
        $fb = $this->factory->createBuilder(FormType::class, $subject, ['data_class' => Brick::class,]);
        $fb->add('type', ChoiceType::class);
        $fb->add('id', HiddenType::class);

        return $fb;
    }

    public function reorder(BrickInterface $brick, int $position): BrickInterface
    {
        $parentBrick = $brick->getParent();
        $children = $parentBrick->getChildren();
        if ($children->contains($brick)) {
            $children->remove($children->indexOf($brick));
        }
        $childrenArray = $children->toArray();
        array_splice($childrenArray, $position, 0, [$brick]);
        $children = new ArrayCollection($childrenArray);

        $i = -1;
        /** @var BrickInterface $child */
        foreach ($children as $child) {
            $child->setPosition(++$i);
        }

        $parentBrick->setChildren($children);

        return $brick;
    }

    public function replicate(BrickInterface $originalBrick, BrickInterface $parent = null): Brick
    {
        $brick = new Brick();
        $brick->setType($originalBrick->getType());
        $brick->setEnabled($originalBrick->isEnabled());

        $originalSettings = $originalBrick->getSettings();

        $settings = [];

        $handler = $this->handlerManager->getHandler($originalBrick);
        $config = $handler->getConfiguration();
        foreach ($config->getSettings() as $setting) {
            $name = $setting->getName();
            if (
                $setting->getType() === EntitySetting::class
            ) {
                if ($setting->getFormType() === ImageType::class) {
                    $settings[$name] = null;
                    if (($image = $originalSettings[$name]) instanceof AbstractImage && $image->getId()) {
                        $newImage = $this->duplicatorService->duplicate($image);

                        $this->em->persist($newImage);
                        $this->em->flush();
                        $this->em->refresh($newImage);

                        $settings[$name] = $this->brickFormat->objectToString($newImage);
                    }
                } else {
                    // default is: no dup for complex cases, can be addressed with custom duplicators, enjoy!
                    $settings[$name] = $originalSettings[$name] ?? null;
                }
            } elseif (
                $setting->getType() === ScalarSetting::class
                || $setting->getType() === ScalarCollectionSetting::class
            ) {
                $settings[$name] = $originalSettings[$name] ?? null;
            } elseif (
                $setting->getType() === SubEntityCollectionSetting::class
                || $setting->getType() === EntityCollectionSetting::class
            ) {
                // default is: no dup for complex cases, can be addressed with custom duplicators, enjoy!
            }
        }

        $brick->setSettings($settings);
        $brick->setPosition($originalBrick->getPosition() + 1);

        foreach ($originalBrick->getChildren() as $idx => $child) {
            $dupChild = $this->replicate($child);

            $dupChild->setPosition($idx);
            $dupChild->setParent($brick);

            $brick->getChildren()->add($dupChild);
        }

        return $brick;
    }
}
