<?php

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\Templating\Entity;

use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Symfony\Component\Clock\ClockInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
use Twig\Error\LoaderError;
use Twig\Error\RuntimeError;
use Twig\Error\SyntaxError;

/**
 * @implements ChillEntityRenderInterface<User>
 */
class UserRender implements ChillEntityRenderInterface
{
    public const SPLIT_LINE_BEFORE_CHARACTER = 'split_lines_before_characters';
    final public const DEFAULT_OPTIONS = [
        'main_scope' => true,
        'user_job' => true,
        'absence' => true,
        'at_date' => null, // instanceof DateTimeInterface
        /*
         * when set, the jobs and service will be splitted in multiple lines. The line will be splitted
         * before the given character. Only for renderString, renderBox is not concerned.
         */
        self::SPLIT_LINE_BEFORE_CHARACTER => null,
    ];

    public function __construct(
        private readonly TranslatableStringHelperInterface $translatableStringHelper,
        private readonly \Twig\Environment $engine,
        private readonly TranslatorInterface $translator,
        private readonly ClockInterface $clock,
    ) {}

    /**
     * @throws LoaderError
     * @throws RuntimeError
     * @throws SyntaxError
     */
    public function renderBox($entity, array $options): string
    {
        $opts = \array_merge(self::DEFAULT_OPTIONS, $options);

        if (null === $opts['at_date']) {
            $opts['at_date'] = $this->clock->now();
        } elseif ($opts['at_date'] instanceof \DateTime) {
            $opts['at_date'] = \DateTimeImmutable::createFromMutable($opts['at_date']);
        }

        return $this->engine->render('@ChillMain/Entity/user.html.twig', [
            'user' => $entity,
            'opts' => $opts,
        ]);
    }

    public function renderString($entity, array $options): string
    {
        $opts = \array_merge(self::DEFAULT_OPTIONS, $options);

        if (null === $opts['at_date']) {
            $opts['at_date'] = $this->clock->now();
        } elseif ($opts['at_date'] instanceof \DateTime) {
            $opts['at_date'] = \DateTimeImmutable::createFromMutable($opts['at_date']);
        }

        $str = $entity->getLabel();

        if (null !== $entity->getUserJob($opts['at_date']) && $opts['user_job']) {
            $str .= ' ('.$this->translatableStringHelper
                ->localize($entity->getUserJob($opts['at_date'])->getLabel()).')';
        }

        if (null !== $entity->getMainScope($opts['at_date']) && $opts['main_scope']) {
            $str .= ' ('.$this->translatableStringHelper
                ->localize($entity->getMainScope($opts['at_date'])->getName()).')';
        }

        if ($entity->isAbsent() && $opts['absence']) {
            $str .= ' ('.$this->translator->trans('absence.Absent').')';
        }

        if (null !== $opts[self::SPLIT_LINE_BEFORE_CHARACTER]) {
            if (!is_int($opts[self::SPLIT_LINE_BEFORE_CHARACTER])) {
                throw new \InvalidArgumentException('Only integer for option split_lines_before_characters is allowed');
            }

            $characterPerLine = $opts[self::SPLIT_LINE_BEFORE_CHARACTER];
            $exploded = explode(' ', $str);
            $charOnLine = 0;
            $str = '';
            foreach ($exploded as $word) {
                if ($charOnLine + strlen($word) > $characterPerLine) {
                    $str .= "\n";
                    $charOnLine = 0;
                }
                if ($charOnLine > 0) {
                    $str .= ' ';
                }
                $str .= $word;
                $charOnLine += strlen($word);
            }
        }

        return $str;
    }

    public function supports($entity, array $options): bool
    {
        return $entity instanceof User;
    }
}
