<?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\Participant;

use Doctrine\ORM\EntityManagerInterface;
use Ferienpass\CoreBundle\Entity\AccessCode;
use Ferienpass\CoreBundle\Entity\AccessCodeStrategy;
use Ferienpass\CoreBundle\Entity\Attendance;
use Ferienpass\CoreBundle\Entity\Consent;
use Ferienpass\CoreBundle\Entity\FriendCode;
use Ferienpass\CoreBundle\Entity\Offer\Base as Offer;
use Ferienpass\CoreBundle\Entity\Participant;
use Ferienpass\CoreBundle\Entity\ParticipantLog;
use Ferienpass\CoreBundle\Entity\User;
use Ferienpass\CoreBundle\Participant\ParticipantMerger;
use PHPUnit\Framework\TestCase;

final class ParticipantMergerTest extends TestCase
{
    public function testMergeMovesAttendancesConsentsAndLogs(): void
    {
        $entityManager = $this->createMock(EntityManagerInterface::class);
        $merger = new ParticipantMerger($entityManager);

        $base = new Participant();
        $merged = new Participant();

        $offer = new Offer();
        $attendance = new Attendance($offer, $merged);
        $merged->addAttendance($attendance);

        $consent = new Consent(new User(), participant: $merged);
        $merged->addConsent($consent);

        $log = new ParticipantLog($merged);
        $merged->addActivity($log);

        $friendCode = new FriendCode($offer, 'CODE1');
        $merged->addFriendCode($friendCode);

        $strategy = $this->createMock(AccessCodeStrategy::class);
        $accessCode = new AccessCode($strategy, 'ACC1');
        $merged->addAccessCode($accessCode);

        // Verify initial state
        self::assertSame($merged, $attendance->getParticipant());
        self::assertSame($merged, $consent->getParticipant());
        self::assertSame($merged, $log->getParticipant());
        self::assertTrue($merged->getFriendCodes()->contains($friendCode));
        self::assertTrue($merged->getAccessCodes()->contains($accessCode));
        self::assertFalse($base->getFriendCodes()->contains($friendCode));
        self::assertFalse($base->getAccessCodes()->contains($accessCode));

        // Expect calls to entity manager
        $entityManager->expects(self::once())->method('remove')->with($merged);
        $entityManager->expects(self::once())->method('flush');

        // Perform merge
        $merger->merge($merged, $base);

        // Verify final state
        self::assertSame($base, $attendance->getParticipant());
        self::assertSame($base, $consent->getParticipant());
        self::assertSame($base, $log->getParticipant());
        self::assertTrue($base->getFriendCodes()->contains($friendCode));
        self::assertTrue($base->getAccessCodes()->contains($accessCode));
    }
}
