<?php

declare(strict_types=1);

/*
 * This file is part of the VITICORE2 package.
 *
 * (c) CP Creation <web@cpcreation.fr>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace CpCreation\VitiCore\Tests\Form;

use CpCreation\VitiCore\Bridge\Symfony\Bundle\Form\Site\Withdrawal\Model\WithdrawalRequestData;
use CpCreation\VitiCore\Bridge\Symfony\Bundle\Form\Site\Withdrawal\WithdrawalRequestType;
use CpCreation\VitiCore\Cart\Model\WithdrawalRequest;
use Symfony\Component\Form\Extension\Validator\ValidatorExtension;
use Symfony\Component\Form\Test\TypeTestCase;
use Symfony\Component\Validator\Validation;

final class WithdrawalRequestTypeTest extends TypeTestCase
{
    public function testItMapsTheLegallyRequiredStatementDetails(): void
    {
        $form = $this->factory->create(WithdrawalRequestType::class, null, ['include_captcha' => false]);
        $form->submit([
            'firstname' => 'Jeanne',
            'lastname' => 'Dupont',
            'contractReference' => 'CMD-123',
            'receiptEmail' => 'jeanne@example.test',
            'orderReceived' => '1',
            'receivedAt' => '2026-06-18',
            'reasonCode' => WithdrawalRequest::REASON_PRODUCT_NOT_AS_EXPECTED,
            'comment' => 'Le carton est arrivé endommagé.',
        ]);

        self::assertTrue($form->isSynchronized());
        self::assertInstanceOf(WithdrawalRequestData::class, $form->getData());
        self::assertSame('Jeanne', $form->getData()->firstname);
        self::assertSame('Dupont', $form->getData()->lastname);
        self::assertSame('CMD-123', $form->getData()->contractReference);
        self::assertSame('jeanne@example.test', $form->getData()->receiptEmail);
        self::assertTrue($form->getData()->orderReceived);
        self::assertSame('2026-06-18', $form->getData()->receivedAt?->format('Y-m-d'));
        self::assertSame(WithdrawalRequest::REASON_PRODUCT_NOT_AS_EXPECTED, $form->getData()->reasonCode);
        self::assertSame('Le carton est arrivé endommagé.', $form->getData()->comment);
    }

    public function testReceptionDateIsRequiredWhenTheOrderWasReceived(): void
    {
        $form = $this->factory->create(WithdrawalRequestType::class, null, ['include_captcha' => false]);
        $form->submit([
            'firstname' => 'Jeanne',
            'lastname' => 'Dupont',
            'contractReference' => 'CMD-123',
            'receiptEmail' => 'jeanne@example.test',
            'orderReceived' => '1',
        ]);

        self::assertFalse($form->isValid());
        self::assertNull($form->getData()->receivedAt);
        self::assertGreaterThan(0, $form->get('receivedAt')->getErrors(true)->count());
    }

    public function testReceptionDateIsNotRequiredWhenTheOrderWasNotReceived(): void
    {
        $form = $this->factory->create(WithdrawalRequestType::class, null, ['include_captcha' => false]);
        $form->submit([
            'firstname' => 'Jeanne',
            'lastname' => 'Dupont',
            'contractReference' => 'CMD-123',
            'receiptEmail' => 'jeanne@example.test',
            'orderReceived' => '0',
        ]);

        self::assertTrue($form->isValid());
        self::assertFalse($form->getData()->orderReceived);
        self::assertNull($form->getData()->receivedAt);
    }

    public function testReceptionChoiceIsRequiredAndFutureDatesAreRejected(): void
    {
        $missingChoiceForm = $this->factory->create(WithdrawalRequestType::class, null, ['include_captcha' => false]);
        $missingChoiceForm->submit([
            'firstname' => 'Jeanne',
            'lastname' => 'Dupont',
            'contractReference' => 'CMD-123',
            'receiptEmail' => 'jeanne@example.test',
        ]);

        self::assertFalse($missingChoiceForm->isValid());
        self::assertGreaterThan(0, $missingChoiceForm->get('orderReceived')->getErrors(true)->count());

        $futureDateForm = $this->factory->create(WithdrawalRequestType::class, null, ['include_captcha' => false]);
        $futureDateForm->submit([
            'firstname' => 'Jeanne',
            'lastname' => 'Dupont',
            'contractReference' => 'CMD-123',
            'receiptEmail' => 'jeanne@example.test',
            'orderReceived' => '1',
            'receivedAt' => '2999-01-01',
        ]);

        self::assertFalse($futureDateForm->isValid());
        self::assertGreaterThan(0, $futureDateForm->get('receivedAt')->getErrors(true)->count());
    }

    public function testUnknownReasonIsRejected(): void
    {
        $form = $this->factory->create(WithdrawalRequestType::class, null, ['include_captcha' => false]);
        $form->submit([
            'firstname' => 'Jeanne',
            'lastname' => 'Dupont',
            'contractReference' => 'CMD-123',
            'receiptEmail' => 'jeanne@example.test',
            'orderReceived' => '0',
            'reasonCode' => 'unknown_reason',
        ]);

        self::assertTrue($form->isSynchronized());
        self::assertFalse($form->isValid());
        self::assertGreaterThan(0, $form->get('reasonCode')->getErrors(true)->count());
    }

    public function testCommentIsOptionalAndLimited(): void
    {
        $emptyCommentForm = $this->factory->create(WithdrawalRequestType::class, null, ['include_captcha' => false]);
        $emptyCommentForm->submit([
            'firstname' => 'Jeanne',
            'lastname' => 'Dupont',
            'contractReference' => 'CMD-123',
            'receiptEmail' => 'jeanne@example.test',
            'orderReceived' => '0',
            'comment' => '',
        ]);

        self::assertTrue($emptyCommentForm->isValid());

        $longCommentForm = $this->factory->create(WithdrawalRequestType::class, null, ['include_captcha' => false]);
        $longCommentForm->submit([
            'firstname' => 'Jeanne',
            'lastname' => 'Dupont',
            'contractReference' => 'CMD-123',
            'receiptEmail' => 'jeanne@example.test',
            'orderReceived' => '0',
            'comment' => str_repeat('a', WithdrawalRequest::COMMENT_MAX_LENGTH + 1),
        ]);

        self::assertFalse($longCommentForm->isValid());
        self::assertGreaterThan(0, $longCommentForm->get('comment')->getErrors(true)->count());
    }

    protected function getExtensions(): array
    {
        return [new ValidatorExtension(
            Validation::createValidatorBuilder()->enableAttributeMapping()->getValidator()
        )];
    }
}
