<?php

declare(strict_types=1);

namespace App\Scolarite\Domain\Model\HomeworkSubmission;

use App\Administration\Domain\Model\User\UserId;
use App\Scolarite\Domain\Event\DevoirRendu;
use App\Scolarite\Domain\Event\DevoirRenduEnRetard;
use App\Scolarite\Domain\Exception\RenduDejaSoumisException;
use App\Scolarite\Domain\Model\Homework\HomeworkId;
use App\Shared\Domain\AggregateRoot;
use App\Shared\Domain\Tenant\TenantId;
use DateTimeImmutable;

final class HomeworkSubmission extends AggregateRoot
{
    public private(set) DateTimeImmutable $updatedAt;

    private function __construct(
        public private(set) HomeworkSubmissionId $id,
        public private(set) TenantId $tenantId,
        public private(set) HomeworkId $homeworkId,
        public private(set) UserId $studentId,
        public private(set) ?string $responseHtml,
        public private(set) SubmissionStatus $status,
        public private(set) ?DateTimeImmutable $submittedAt,
        public private(set) DateTimeImmutable $createdAt,
    ) {
        $this->updatedAt = $createdAt;
    }

    public static function creerBrouillon(
        TenantId $tenantId,
        HomeworkId $homeworkId,
        UserId $studentId,
        ?string $responseHtml,
        DateTimeImmutable $now,
    ): self {
        return new self(
            id: HomeworkSubmissionId::generate(),
            tenantId: $tenantId,
            homeworkId: $homeworkId,
            studentId: $studentId,
            responseHtml: $responseHtml,
            status: SubmissionStatus::DRAFT,
            submittedAt: null,
            createdAt: $now,
        );
    }

    public function modifierBrouillon(?string $responseHtml, DateTimeImmutable $now): void
    {
        if (!$this->status->estModifiable()) {
            throw RenduDejaSoumisException::pourRendu($this->id);
        }

        $this->responseHtml = $responseHtml;
        $this->updatedAt = $now;
    }

    public function soumettre(DateTimeImmutable $dueDate, DateTimeImmutable $now): void
    {
        if (!$this->status->estModifiable()) {
            throw RenduDejaSoumisException::pourRendu($this->id);
        }

        $this->submittedAt = $now;
        $this->updatedAt = $now;

        $estEnRetard = $now > $dueDate;

        $this->status = $estEnRetard
            ? SubmissionStatus::LATE
            : SubmissionStatus::SUBMITTED;

        if ($estEnRetard) {
            $this->recordEvent(new DevoirRenduEnRetard(
                submissionId: $this->id,
                homeworkId: $this->homeworkId,
                studentId: $this->studentId,
                tenantId: $this->tenantId,
                occurredOn: $now,
            ));
        } else {
            $this->recordEvent(new DevoirRendu(
                submissionId: $this->id,
                homeworkId: $this->homeworkId,
                studentId: $this->studentId,
                tenantId: $this->tenantId,
                occurredOn: $now,
            ));
        }
    }

    /**
     * @internal Pour usage Infrastructure uniquement
     */
    public static function reconstitute(
        HomeworkSubmissionId $id,
        TenantId $tenantId,
        HomeworkId $homeworkId,
        UserId $studentId,
        ?string $responseHtml,
        SubmissionStatus $status,
        ?DateTimeImmutable $submittedAt,
        DateTimeImmutable $createdAt,
        DateTimeImmutable $updatedAt,
    ): self {
        $submission = new self(
            id: $id,
            tenantId: $tenantId,
            homeworkId: $homeworkId,
            studentId: $studentId,
            responseHtml: $responseHtml,
            status: $status,
            submittedAt: $submittedAt,
            createdAt: $createdAt,
        );

        $submission->updatedAt = $updatedAt;

        return $submission;
    }
}
