<?php

declare(strict_types=1);

namespace App\Tests\Unit\Administration\Application\Command\UnlinkParentFromStudent;

use App\Administration\Application\Command\UnlinkParentFromStudent\UnlinkParentFromStudentCommand;
use App\Administration\Application\Command\UnlinkParentFromStudent\UnlinkParentFromStudentHandler;
use App\Administration\Domain\Event\ParentDelieDEleve;
use App\Administration\Domain\Exception\StudentGuardianNotFoundException;
use App\Administration\Domain\Model\StudentGuardian\RelationshipType;
use App\Administration\Domain\Model\StudentGuardian\StudentGuardian;
use App\Administration\Domain\Model\User\UserId;
use App\Administration\Infrastructure\Persistence\InMemory\InMemoryStudentGuardianRepository;
use App\Shared\Domain\Clock;
use App\Shared\Domain\Tenant\TenantId;
use DateTimeImmutable;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase;

final class UnlinkParentFromStudentHandlerTest extends TestCase
{
    private const string TENANT_ID = '550e8400-e29b-41d4-a716-446655440001';
    private const string STUDENT_ID = '550e8400-e29b-41d4-a716-446655440002';
    private const string GUARDIAN_ID = '550e8400-e29b-41d4-a716-446655440003';

    private InMemoryStudentGuardianRepository $repository;
    private UnlinkParentFromStudentHandler $handler;

    protected function setUp(): void
    {
        $this->repository = new InMemoryStudentGuardianRepository();
        $clock = new class implements Clock {
            public function now(): DateTimeImmutable
            {
                return new DateTimeImmutable('2026-02-10 10:00:00');
            }
        };
        $this->handler = new UnlinkParentFromStudentHandler($this->repository, $clock);
    }

    #[Test]
    public function unlinkRemovesExistingLink(): void
    {
        $link = $this->createAndSaveLink();

        ($this->handler)(new UnlinkParentFromStudentCommand(
            linkId: (string) $link->id,
            tenantId: self::TENANT_ID,
        ));

        self::assertSame(0, $this->repository->countGuardiansForStudent(
            $link->studentId,
            $link->tenantId,
        ));
    }

    #[Test]
    public function unlinkRecordsParentDelieDEleveEvent(): void
    {
        $link = $this->createAndSaveLink();

        $result = ($this->handler)(new UnlinkParentFromStudentCommand(
            linkId: (string) $link->id,
            tenantId: self::TENANT_ID,
        ));

        $events = $result->pullDomainEvents();
        self::assertCount(1, $events);
        self::assertInstanceOf(ParentDelieDEleve::class, $events[0]);
        self::assertTrue($events[0]->studentId->equals($link->studentId));
        self::assertTrue($events[0]->guardianId->equals($link->guardianId));
    }

    #[Test]
    public function throwsWhenLinkNotFound(): void
    {
        $this->expectException(StudentGuardianNotFoundException::class);

        ($this->handler)(new UnlinkParentFromStudentCommand(
            linkId: '550e8400-e29b-41d4-a716-446655440099',
            tenantId: self::TENANT_ID,
        ));
    }

    private function createAndSaveLink(): StudentGuardian
    {
        $link = StudentGuardian::lier(
            studentId: UserId::fromString(self::STUDENT_ID),
            guardianId: UserId::fromString(self::GUARDIAN_ID),
            relationshipType: RelationshipType::FATHER,
            tenantId: TenantId::fromString(self::TENANT_ID),
            createdAt: new DateTimeImmutable('2026-02-10 10:00:00'),
        );
        // Drain lier() events so only delier() events are tested
        $link->pullDomainEvents();
        $this->repository->save($link);

        return $link;
    }
}
