<?php

declare(strict_types=1);

namespace CpCreation\VitiCore\Tests\Marketing;

use CpCreation\VitiCore\Bridge\Symfony\Bundle\Validator\Constraints\Translation;
use CpCreation\VitiCore\Marketing\Model\ReviewRequestConfiguration;
use CpCreation\VitiCore\Marketing\Model\Translation\ReviewRequestConfigurationTranslation;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\Validator\ConstraintValidatorFactory;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use Symfony\Component\Validator\Validation;

final class ReviewRequestConfigurationTest extends TestCase
{
    public function testCollectionIsDisabledByDefaultWithConservativeSettings(): void
    {
        $configuration = new ReviewRequestConfiguration();

        self::assertFalse($configuration->isEnabled());
        self::assertSame(10, $configuration->getSendDelayDays());
        self::assertSame(90, $configuration->getTokenLifetimeDays());
        self::assertFalse($configuration->isSecondReminderEnabled());
        self::assertSame(7, $configuration->getSecondReminderDelayDays());
        self::assertTrue($configuration->isModerationRequired());
        self::assertNull($configuration->getGoogleBusinessReviewUrl());
        self::assertInstanceOf(\DateTimeImmutable::class, $configuration->getFulfilledAfter());
    }

    public function testGoogleBusinessReviewUrlIsNormalizedAndValidated(): void
    {
        $configuration = new ReviewRequestConfiguration();
        $configuration->setGoogleBusinessReviewUrl('  https://g.page/r/example/review  ');

        self::assertSame(
            'https://g.page/r/example/review',
            $configuration->getGoogleBusinessReviewUrl(),
        );

        $validator = $this->createValidator();

        self::assertCount(0, $validator->validate($configuration));

        $configuration->setGoogleBusinessReviewUrl('javascript:alert(1)');
        self::assertCount(1, $validator->validate($configuration));

        $configuration->setGoogleBusinessReviewUrl('   ');
        self::assertNull($configuration->getGoogleBusinessReviewUrl());
        self::assertCount(0, $validator->validate($configuration));
    }

    public function testPolicyAdditionalContentIsTranslatedWithFrenchFallback(): void
    {
        $configuration = new ReviewRequestConfiguration();
        $french = $configuration->translate('fr', false);
        $english = $configuration->translate('en', false);

        self::assertInstanceOf(ReviewRequestConfigurationTranslation::class, $french);
        self::assertInstanceOf(ReviewRequestConfigurationTranslation::class, $english);

        $french->setPolicyAdditionalContent('  <p>Complément français</p>  ');
        $english->setPolicyAdditionalContent('  <p>English addition</p>  ');

        self::assertSame(
            '<p>Complément français</p>',
            $configuration->getPolicyAdditionalContentForLocale('fr'),
        );
        self::assertSame(
            '<p>English addition</p>',
            $configuration->getPolicyAdditionalContentForLocale('en'),
        );
        self::assertSame(
            '<p>Complément français</p>',
            $configuration->getPolicyAdditionalContentForLocale('de'),
        );
    }

    public function testLocalizedEmailTitleIsNormalized(): void
    {
        $configuration = new ReviewRequestConfiguration();
        $french = $configuration->translate('fr', false);

        self::assertInstanceOf(ReviewRequestConfigurationTranslation::class, $french);
        $french->setEmailTitle("  Votre avis\ncompte  ");

        self::assertSame('Votre avis compte', $configuration->getEmailTitleForLocale('fr_FR'));
        self::assertNull($configuration->getEmailTitleForLocale('en'));
    }

    public function testEnabledSecondReminderMustBeSentBeforeTheLinkExpires(): void
    {
        $configuration = new ReviewRequestConfiguration();
        $configuration->setTokenLifetimeDays(7);
        $configuration->setSecondReminderDelayDays(7);

        $validator = $this->createValidator();

        self::assertCount(0, $validator->validate($configuration));

        $configuration->setSecondReminderEnabled(true);
        $violations = $validator->validate($configuration);

        self::assertCount(1, $violations);
        self::assertSame('secondReminderDelayDays', $violations[0]->getPropertyPath());

        $configuration->setSecondReminderDelayDays(6);

        self::assertCount(0, $validator->validate($configuration));
    }

    private function createValidator(): ValidatorInterface
    {
        $translationValidator = new class extends ConstraintValidator {
            public function validate(mixed $value, Constraint $constraint): void {}
        };

        return Validation::createValidatorBuilder()
            ->enableAttributeMapping()
            ->setConstraintValidatorFactory(new ConstraintValidatorFactory([
                new Translation()->validatedBy() => $translationValidator,
            ]))
            ->getValidator();
    }
}
