<?php

declare(strict_types=1);

namespace App\Tests\Unit\Shared\Domain;

use App\Shared\Domain\AggregateRoot;
use App\Shared\Domain\DomainEvent;
use DateTimeImmutable;
use PHPUnit\Framework\TestCase;
use Ramsey\Uuid\Uuid;
use Ramsey\Uuid\UuidInterface;

final class AggregateRootTest extends TestCase
{
    public function testPullDomainEventsReturnsRecordedEvents(): void
    {
        $aggregate = new TestAggregate();
        $event1 = new TestDomainEvent('test1');
        $event2 = new TestDomainEvent('test2');

        $aggregate->doSomething($event1);
        $aggregate->doSomething($event2);

        $events = $aggregate->pullDomainEvents();

        $this->assertCount(2, $events);
        $this->assertSame($event1, $events[0]);
        $this->assertSame($event2, $events[1]);
    }

    public function testPullDomainEventsClearsEventsAfterPulling(): void
    {
        $aggregate = new TestAggregate();
        $event = new TestDomainEvent('test');

        $aggregate->doSomething($event);
        $aggregate->pullDomainEvents();

        $secondPull = $aggregate->pullDomainEvents();

        $this->assertCount(0, $secondPull);
    }

    public function testRecordEventAddsEventToInternalList(): void
    {
        $aggregate = new TestAggregate();
        $event = new TestDomainEvent('test');

        $aggregate->doSomething($event);
        $events = $aggregate->pullDomainEvents();

        $this->assertCount(1, $events);
        $this->assertInstanceOf(TestDomainEvent::class, $events[0]);
    }
}

// Test implementations
final class TestAggregate extends AggregateRoot
{
    public function doSomething(DomainEvent $event): void
    {
        $this->recordEvent($event);
    }
}

final readonly class TestDomainEvent implements DomainEvent
{
    private DateTimeImmutable $occurredOn;

    public function __construct(
        public string $data,
        private ?UuidInterface $testAggregateId = null,
    ) {
        $this->occurredOn = new DateTimeImmutable();
    }

    public function occurredOn(): DateTimeImmutable
    {
        return $this->occurredOn;
    }

    public function aggregateId(): UuidInterface
    {
        return $this->testAggregateId ?? Uuid::uuid7();
    }
}
