<?php

/**
 * Chill is a software for social workers.
 *
 * For the full copyright and license information, please view
 * the LICENSE file that was distributed with this source code.
 */

declare(strict_types=1);

/*
 * Chill is a software for social workers
 *
 * For the full copyright and license information, please view
 * the LICENSE file that was distributed with this source code.
 */

namespace Chill\MainBundle\Form\DataTransformer;

use Doctrine\Persistence\ObjectRepository;
use Symfony\Component\Form\DataTransformerInterface;
use Symfony\Component\Form\Exception\TransformationFailedException;

/**
 * @template T
 */
class IdToEntityDataTransformer implements DataTransformerInterface
{
    private readonly \Closure $getId;

    /**
     * @param \Closure $getId
     */
    public function __construct(
        private readonly ObjectRepository $repository,
        private readonly bool $multiple = false,
        ?callable $getId = null,
    ) {
        $this->getId = $getId ?? static fn (object $o) => $o->getId();
    }

    /**
     * @param string $value
     *
     * @return array|object[]|T[]|T|object
     */
    public function reverseTransform($value)
    {
        if ($this->multiple) {
            if (null === $value | '' === $value) {
                return [];
            }

            return array_map(
                fn (string $id): ?object => $this->repository->findOneBy(['id' => (int) $id]),
                explode(',', $value)
            );
        }

        if (null === $value | '' === $value) {
            return null;
        }

        $object = $this->repository->findOneBy(['id' => (int) $value]);

        if (null === $object) {
            throw new TransformationFailedException('could not find any object by object id');
        }

        return $object;
    }

    /**
     * @param object|T|object[]|T[] $value
     */
    public function transform($value): string
    {
        if ($this->multiple) {
            $ids = [];

            foreach ($value as $v) {
                $ids[] = $id = \call_user_func($this->getId, $v);

                if (null === $id) {
                    throw new TransformationFailedException('id is null');
                }
            }

            return implode(',', $ids);
        }

        if (null === $value) {
            return '';
        }

        $id = \call_user_func($this->getId, $value);

        if (null === $id) {
            throw new TransformationFailedException('id is null');
        }

        return (string) $id;
    }
}
