<?php

declare(strict_types=1);

namespace App\Administration\Domain\Model\StudentGuardian;

use App\Administration\Domain\Event\ParentDelieDEleve;
use App\Administration\Domain\Event\ParentLieAEleve;
use App\Administration\Domain\Model\User\UserId;
use App\Shared\Domain\AggregateRoot;
use App\Shared\Domain\Tenant\TenantId;
use DateTimeImmutable;

/**
 * Aggregate Root représentant la liaison entre un parent/tuteur et un élève.
 *
 * Un élève peut avoir au maximum 2 parents/tuteurs liés (contrainte métier).
 * La vérification du maximum est faite au niveau Application Layer via le repository.
 *
 * @see FR6: Le parent peut suivre la scolarité de ses enfants
 */
final class StudentGuardian extends AggregateRoot
{
    public const int MAX_GUARDIANS_PER_STUDENT = 2;

    private function __construct(
        public private(set) StudentGuardianId $id,
        public private(set) UserId $studentId,
        public private(set) UserId $guardianId,
        public private(set) RelationshipType $relationshipType,
        public private(set) TenantId $tenantId,
        public private(set) DateTimeImmutable $createdAt,
        public private(set) ?UserId $createdBy,
    ) {
    }

    /**
     * Crée une liaison parent-élève.
     */
    public static function lier(
        UserId $studentId,
        UserId $guardianId,
        RelationshipType $relationshipType,
        TenantId $tenantId,
        DateTimeImmutable $createdAt,
        ?UserId $createdBy = null,
    ): self {
        $link = new self(
            id: StudentGuardianId::generate(),
            studentId: $studentId,
            guardianId: $guardianId,
            relationshipType: $relationshipType,
            tenantId: $tenantId,
            createdAt: $createdAt,
            createdBy: $createdBy,
        );

        $link->recordEvent(new ParentLieAEleve(
            linkId: $link->id,
            studentId: $link->studentId,
            guardianId: $link->guardianId,
            relationshipType: $link->relationshipType,
            tenantId: $link->tenantId,
            occurredOn: $createdAt,
        ));

        return $link;
    }

    /**
     * Enregistre un événement de suppression de liaison.
     */
    public function delier(DateTimeImmutable $at): void
    {
        $this->recordEvent(new ParentDelieDEleve(
            linkId: $this->id,
            studentId: $this->studentId,
            guardianId: $this->guardianId,
            tenantId: $this->tenantId,
            occurredOn: $at,
        ));
    }

    /**
     * Reconstitue une liaison depuis le stockage.
     *
     * @internal Pour usage Infrastructure uniquement
     */
    public static function reconstitute(
        StudentGuardianId $id,
        UserId $studentId,
        UserId $guardianId,
        RelationshipType $relationshipType,
        TenantId $tenantId,
        DateTimeImmutable $createdAt,
        ?UserId $createdBy,
    ): self {
        return new self(
            id: $id,
            studentId: $studentId,
            guardianId: $guardianId,
            relationshipType: $relationshipType,
            tenantId: $tenantId,
            createdAt: $createdAt,
            createdBy: $createdBy,
        );
    }
}
