<?php

declare(strict_types=1);

/*
 * This file is part of the Ferienpass package.
 *
 * (c) Richard Henkenjohann <richard@ferienpass.online>
 *
 * For more information visit the project website <https://ferienpass.online>
 * or the documentation under <https://docs.ferienpass.online>.
 */

namespace Ferienpass\CoreBundle\Tests\ConsentManager;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\EntityManagerInterface;
use Ferienpass\CoreBundle\ConsentManager\ConsentManager;
use Ferienpass\CoreBundle\Entity\Consent;
use Ferienpass\CoreBundle\Entity\ConsentForm;
use Ferienpass\CoreBundle\Entity\Offer\OfferInterface;
use Ferienpass\CoreBundle\Entity\Participant\ParticipantInterface;
use Ferienpass\CoreBundle\Entity\User;
use Ferienpass\CoreBundle\Repository\ConsentFormRepository;
use Ferienpass\CoreBundle\Repository\ConsentRepository;
use PHPUnit\Framework\TestCase;

final class ConsentManagerForceDecisionTest extends TestCase
{
    public function testAccountSubjectSelectsSignatureForGivenUser(): void
    {
        $consentFormRepository = $this->createStub(ConsentFormRepository::class);
        $consentRepository = $this->createStub(ConsentRepository::class);
        $entityManager = $this->createStub(EntityManagerInterface::class);

        $userA = $this->createStub(User::class);
        $userA->method('getId')->willReturn(1);
        $userB = $this->createStub(User::class);
        $userB->method('getId')->willReturn(2);
        $participant = $this->createStub(ParticipantInterface::class);
        $offer = $this->createStub(OfferInterface::class);
        $edition = $this->createStub(\Ferienpass\CoreBundle\Entity\Edition::class);
        $offer->method('getEdition')->willReturn($edition);

        $consentForm = $this->createStub(ConsentForm::class);
        $consentForm->method('getSubject')->willReturn('account');
        $consentForm->method('getText')->willReturn('current text');
        $signatureA = new Consent($userA, consentForm: $consentForm, decision: 1);
        $signatureB = new Consent($userB, consentForm: $consentForm, decision: 0);
        $consentForm->method('getSignatures')->willReturn(new ArrayCollection([
            $signatureA,
            $signatureB,
        ]));

        $consentFormRepository
            ->method('findForOffer')
            ->willReturn([$consentForm]);

        $consentRepository->method('findSignatures')->willReturn([$signatureA, $signatureB]);

        $manager = new ConsentManager($consentFormRepository, $consentRepository, $entityManager);

        $states = $manager->forOfferAndParticipants($offer, [$participant], $userA);

        self::assertCount(1, $states);
        self::assertTrue($states[0]->isAcknowledged());
        self::assertTrue($states[0]->isSigned());
    }

    public function testSignatureInvalidWhenTextChanges(): void
    {
        $consentFormRepository = $this->createStub(ConsentFormRepository::class);
        $consentRepository = $this->createStub(ConsentRepository::class);
        $entityManager = $this->createStub(EntityManagerInterface::class);

        $user = $this->createStub(User::class);
        $participant = $this->createStub(ParticipantInterface::class);
        $offer = $this->createStub(OfferInterface::class);
        $edition = $this->createStub(\Ferienpass\CoreBundle\Entity\Edition::class);
        $offer->method('getEdition')->willReturn($edition);

        $consentForm = $this->createStub(ConsentForm::class);
        $consentForm->method('getSubject')->willReturn('account');
        $consentForm->method('getText')->willReturn('NEW text');

        // Signature was created for 'old text'
        $signature = new Consent($user, consentForm: $consentForm, decision: 1);
        $refl = new \ReflectionProperty(Consent::class, 'hash');
        $refl->setAccessible(true);
        $refl->setValue($signature, hash('sha256', 'old text'));

        $consentForm->method('getSignatures')->willReturn(new ArrayCollection([$signature]));

        $consentFormRepository
            ->method('findForOffer')
            ->willReturn([$consentForm]);

        $consentRepository->method('findSignatures')->willReturn([$signature]);

        $manager = new ConsentManager($consentFormRepository, $consentRepository, $entityManager);

        $states = $manager->forOfferAndParticipants($offer, [$participant], $user);

        self::assertCount(1, $states);
        self::assertFalse($states[0]->isAcknowledged(), 'Should not be acknowledged because text changed');
        self::assertFalse($states[0]->isSigned(), 'Should not be signed because text changed');
    }
}
