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

use Doctrine\ORM\EntityManagerInterface;
use Ferienpass\CoreBundle\Entity\MessengerLog;
use Ferienpass\CoreBundle\Entity\Offer\Base;
use Ferienpass\CoreBundle\Entity\OfferAttachment;
use Ferienpass\CoreBundle\Entity\OfferDate;
use Ferienpass\CoreBundle\Entity\OfferMedia;
use Ferienpass\CoreBundle\Entity\OfferMemberAssociation;
use Ferienpass\CoreBundle\Repository\OfferRepository;
use PHPUnit\Framework\TestCase;

class OfferRepositoryTest extends TestCase
{
    private OfferRepository $repository;

    protected function setUp(): void
    {
        $entityManager = $this->createMock(EntityManagerInterface::class);
        $classMetadata = new \Doctrine\ORM\Mapping\ClassMetadata(Base::class);

        $this->repository = new OfferRepository($entityManager, $classMetadata);
    }

    public function testCreateCopyClonesSubEntities(): void
    {
        $originalOffer = new Base();
        $this->setEntityId($originalOffer, 1);
        $originalUuid = $originalOffer->getUuid();

        $media = new OfferMedia(offer: $originalOffer);
        $this->setEntityId($media, 10);
        $mediaUuid = $media->getUuid();
        $originalOffer->addMedia($media);

        $attachment = new OfferAttachment(offer: $originalOffer);
        $this->setEntityId($attachment, 20);
        $attachmentUuid = $attachment->getUuid();
        $originalOffer->addAttachment($attachment);

        $memberAssoc = new OfferMemberAssociation();
        $memberAssoc->setOffer($originalOffer);
        $this->setEntityId($memberAssoc, 30);
        $assocUuid = $memberAssoc->getUuid();
        $originalOffer->addMemberAssociation($memberAssoc);

        $date = new OfferDate($originalOffer);
        $this->setEntityId($date, 40);
        $dateUuid = $date->getUuid();
        $originalOffer->addDate($date);

        $log = new MessengerLog('Test message');
        $this->setEntityId($log, 50);
        $reflectionLogs = new \ReflectionProperty(Base::class, 'messengerLogs');
        $reflectionLogs->setAccessible(true);
        $logs = $reflectionLogs->getValue($originalOffer);
        $logs->add($log);

        $copy = $this->repository->createCopy($originalOffer);

        // Verify Offer
        $this->assertNotSame($originalOffer, $copy);
        $this->assertNull($copy->getId());
        $this->assertNotSame($originalUuid->toRfc4122(), $copy->getUuid()->toRfc4122());

        // Verify Media
        $this->assertCount(1, $copy->getMedia());
        $clonedMedia = $copy->getMedia()->first();
        $this->assertNotSame($media, $clonedMedia);
        $this->assertSame($copy, $clonedMedia->getOffer());
        $this->assertNull($clonedMedia->getId());
        $this->assertNotSame($mediaUuid->toRfc4122(), $clonedMedia->getUuid()->toRfc4122());

        // Verify Attachment
        $this->assertCount(1, $copy->getAttachments());
        $clonedAttachment = $copy->getAttachments()->first();
        $this->assertNotSame($attachment, $clonedAttachment);
        $this->assertSame($copy, $clonedAttachment->getOffer());
        $this->assertNull($clonedAttachment->getId());
        $this->assertNotSame($attachmentUuid->toRfc4122(), $clonedAttachment->getUuid()->toRfc4122());

        // Verify MemberAssociation
        $this->assertCount(1, $copy->getMemberAssociations());
        $clonedMemberAssoc = $copy->getMemberAssociations()->first();
        $this->assertNotSame($memberAssoc, $clonedMemberAssoc);
        $this->assertSame($copy, $clonedMemberAssoc->getOffer());
        $this->assertNull($clonedMemberAssoc->getId());
        $this->assertNotSame($assocUuid->toRfc4122(), $clonedMemberAssoc->getUuid()->toRfc4122());

        // Verify Date
        $this->assertCount(1, $copy->getDates());
        $clonedDate = $copy->getDates()->first();
        $this->assertNotSame($date, $clonedDate);
        $this->assertSame($copy, $clonedDate->getOffer());
        $this->assertNull($clonedDate->getId());
        $this->assertNotSame($dateUuid->toRfc4122(), $clonedDate->getUuid()->toRfc4122());

        // Verify MessengerLog is NOT copied
        $this->assertCount(0, $copy->getMessengerLogs());
    }

    private function setEntityId(object $entity, int $id): void
    {
        $reflection = new \ReflectionProperty($entity, 'id');
        $reflection->setAccessible(true);
        $reflection->setValue($entity, $id);
    }
}
