<?php

declare(strict_types=1);

namespace App\Scolarite\Domain\Model\Homework;

use App\Administration\Domain\Model\User\UserId;
use App\Scolarite\Domain\Event\ExceptionDevoirDemandee;
use App\Scolarite\Domain\Exception\JustificationTropCourteException;
use App\Shared\Domain\AggregateRoot;
use App\Shared\Domain\Tenant\TenantId;
use DateTimeImmutable;

use function explode;
use function implode;
use function mb_strlen;

final class HomeworkRuleException extends AggregateRoot
{
    private const int JUSTIFICATION_MIN_LENGTH = 20;

    private function __construct(
        public private(set) HomeworkRuleExceptionId $id,
        public private(set) TenantId $tenantId,
        public private(set) HomeworkId $homeworkId,
        public private(set) string $ruleType,
        public private(set) string $justification,
        public private(set) UserId $createdBy,
        public private(set) DateTimeImmutable $createdAt,
    ) {
    }

    /**
     * @param string[] $ruleTypes Types de règles contournées
     */
    public static function demander(
        TenantId $tenantId,
        HomeworkId $homeworkId,
        array $ruleTypes,
        string $justification,
        UserId $createdBy,
        DateTimeImmutable $now,
    ): self {
        if (mb_strlen($justification) < self::JUSTIFICATION_MIN_LENGTH) {
            throw JustificationTropCourteException::avecMinimum(self::JUSTIFICATION_MIN_LENGTH);
        }

        $ruleType = implode(',', $ruleTypes);

        $exception = new self(
            id: HomeworkRuleExceptionId::generate(),
            tenantId: $tenantId,
            homeworkId: $homeworkId,
            ruleType: $ruleType,
            justification: $justification,
            createdBy: $createdBy,
            createdAt: $now,
        );

        $exception->recordEvent(new ExceptionDevoirDemandee(
            exceptionId: $exception->id,
            tenantId: $tenantId,
            homeworkId: $homeworkId,
            ruleTypes: $ruleTypes,
            justification: $justification,
            createdBy: $createdBy,
            occurredOn: $now,
        ));

        return $exception;
    }

    /** @return string[] */
    public function ruleTypes(): array
    {
        return explode(',', $this->ruleType);
    }

    /**
     * @internal Pour usage Infrastructure uniquement
     */
    public static function reconstitute(
        HomeworkRuleExceptionId $id,
        TenantId $tenantId,
        HomeworkId $homeworkId,
        string $ruleType,
        string $justification,
        UserId $createdBy,
        DateTimeImmutable $createdAt,
    ): self {
        return new self(
            id: $id,
            tenantId: $tenantId,
            homeworkId: $homeworkId,
            ruleType: $ruleType,
            justification: $justification,
            createdBy: $createdBy,
            createdAt: $createdAt,
        );
    }
}
