<?php

declare(strict_types=1);

namespace App\Scolarite\Domain\Model\Homework;

use App\Administration\Domain\Model\SchoolClass\ClassId;
use App\Administration\Domain\Model\Subject\SubjectId;
use App\Administration\Domain\Model\User\UserId;
use App\Scolarite\Domain\Event\DevoirCree;
use App\Scolarite\Domain\Event\DevoirModifie;
use App\Scolarite\Domain\Event\DevoirSupprime;
use App\Scolarite\Domain\Exception\DevoirDejaSupprimeException;
use App\Shared\Domain\AggregateRoot;
use App\Shared\Domain\Tenant\TenantId;
use DateTimeImmutable;

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

    /** @var array{warnings: string[], acknowledgedAt: string}|null */
    public private(set) ?array $ruleOverride = null;

    private function __construct(
        public private(set) HomeworkId $id,
        public private(set) TenantId $tenantId,
        public private(set) ClassId $classId,
        public private(set) SubjectId $subjectId,
        public private(set) UserId $teacherId,
        public private(set) string $title,
        public private(set) ?string $description,
        public private(set) DateTimeImmutable $dueDate,
        public private(set) HomeworkStatus $status,
        public private(set) DateTimeImmutable $createdAt,
    ) {
        $this->updatedAt = $createdAt;
    }

    /**
     * @param string[] $ruleTypes Types de règles contournées (ex: ['minimum_delay'])
     */
    public function acknowledgeRuleWarning(array $ruleTypes, DateTimeImmutable $now): void
    {
        $this->ruleOverride = [
            'warnings' => $ruleTypes,
            'acknowledgedAt' => $now->format(DateTimeImmutable::ATOM),
        ];
    }

    public static function creer(
        TenantId $tenantId,
        ClassId $classId,
        SubjectId $subjectId,
        UserId $teacherId,
        string $title,
        ?string $description,
        DateTimeImmutable $dueDate,
        DateTimeImmutable $now,
    ): self {
        $homework = new self(
            id: HomeworkId::generate(),
            tenantId: $tenantId,
            classId: $classId,
            subjectId: $subjectId,
            teacherId: $teacherId,
            title: $title,
            description: $description,
            dueDate: $dueDate,
            status: HomeworkStatus::PUBLISHED,
            createdAt: $now,
        );

        $homework->recordEvent(new DevoirCree(
            homeworkId: $homework->id,
            classId: (string) $classId,
            subjectId: (string) $subjectId,
            teacherId: (string) $teacherId,
            title: $title,
            dueDate: $dueDate,
            occurredOn: $now,
        ));

        return $homework;
    }

    public function modifier(
        string $title,
        ?string $description,
        DateTimeImmutable $dueDate,
        DateTimeImmutable $now,
    ): void {
        if ($this->status === HomeworkStatus::DELETED) {
            throw DevoirDejaSupprimeException::withId($this->id);
        }

        $this->title = $title;
        $this->description = $description;
        $this->dueDate = $dueDate;
        $this->updatedAt = $now;

        $this->recordEvent(new DevoirModifie(
            homeworkId: $this->id,
            title: $title,
            dueDate: $dueDate,
            occurredOn: $now,
        ));
    }

    public function supprimer(DateTimeImmutable $now): void
    {
        if ($this->status === HomeworkStatus::DELETED) {
            throw DevoirDejaSupprimeException::withId($this->id);
        }

        $this->status = HomeworkStatus::DELETED;
        $this->updatedAt = $now;

        $this->recordEvent(new DevoirSupprime(
            homeworkId: $this->id,
            occurredOn: $now,
        ));
    }

    /**
     * @internal Pour usage Infrastructure uniquement
     *
     * @param array{warnings: string[], acknowledgedAt: string}|null $ruleOverride
     */
    public static function reconstitute(
        HomeworkId $id,
        TenantId $tenantId,
        ClassId $classId,
        SubjectId $subjectId,
        UserId $teacherId,
        string $title,
        ?string $description,
        DateTimeImmutable $dueDate,
        HomeworkStatus $status,
        DateTimeImmutable $createdAt,
        DateTimeImmutable $updatedAt,
        ?array $ruleOverride = null,
    ): self {
        $homework = new self(
            id: $id,
            tenantId: $tenantId,
            classId: $classId,
            subjectId: $subjectId,
            teacherId: $teacherId,
            title: $title,
            description: $description,
            dueDate: $dueDate,
            status: $status,
            createdAt: $createdAt,
        );

        $homework->updatedAt = $updatedAt;
        $homework->ruleOverride = $ruleOverride;

        return $homework;
    }
}
