<?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\PersonBundle\Validator\Constraints\Person;

use Symfony\Component\Clock\ClockInterface;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\Validator\Exception\UnexpectedTypeException;

class BirthdateValidator extends ConstraintValidator
{
    private readonly string $interval_spec;

    private string $below_interval = 'P150Y';

    public function __construct(
        private readonly ParameterBagInterface $parameterBag,
        private readonly ClockInterface $clock,
    ) {
        $this->interval_spec = $this->parameterBag->get('chill_person')['validation']['birthdate_not_after'];
    }

    public function validate($value, Constraint $constraint)
    {
        if (null === $value) {
            return;
        }

        if (!$value instanceof \DateTime) {
            throw new \LogicException('The input should a be a \DateTime interface,'.get_debug_type($value));
        }

        if (!$constraint instanceof Birthdate) {
            throw new UnexpectedTypeException($constraint, Birthdate::class);
        }

        $limitDate = $this->getLimitDate();

        if ($value > $limitDate) {
            $this->context->buildViolation($constraint->message)
                ->setParameter('%date%', $limitDate->format('d-m-Y'))
                ->setCode(Birthdate::BIRTHDATE_INVALID_CODE)
                ->addViolation();
        }

        if ($value < $this->getBelowLimitDate()) {
            $this->context->buildViolation($constraint->belowMessage)
                ->setParameter('%date%', $this->getBelowLimitDate()->format('d-m-Y'))
                ->setCode(Birthdate::BIRTHDATE_INVALID_CODE)
                ->addViolation();
        }
    }

    private function getLimitDate(): \DateTime
    {
        $interval = new \DateInterval($this->interval_spec);

        return \DateTime::createFromImmutable($this->clock->now()->sub($interval));
    }

    private function getBelowLimitDate(): \DateTime
    {
        return \DateTime::createFromImmutable($this->clock->now()->sub(new \DateInterval($this->below_interval)));
    }
}
