<?php

declare(strict_types=1);

namespace App\Scolarite\Domain\Service;

use App\Scolarite\Domain\Model\Schedule\ScheduleSlot;
use App\Scolarite\Domain\Model\Schedule\ScheduleSlotId;
use App\Scolarite\Domain\Repository\ScheduleSlotRepository;
use App\Shared\Domain\Tenant\TenantId;

/**
 * Détecte les conflits de créneaux dans l'emploi du temps.
 *
 * Vérifie les conflits enseignant (même enseignant, même créneau horaire)
 * et les conflits de salle (même salle, même créneau horaire).
 */
final readonly class ScheduleConflictDetector
{
    public function __construct(
        private ScheduleSlotRepository $repository,
    ) {
    }

    /**
     * @return array<ScheduleConflict>
     */
    public function detectConflicts(
        ScheduleSlot $slot,
        TenantId $tenantId,
        ?ScheduleSlotId $excludeId = null,
    ): array {
        $conflicts = [];

        $classConflicts = $this->repository->findOverlappingForClass(
            $slot->classId,
            $slot->dayOfWeek,
            $slot->timeSlot->startTime,
            $slot->timeSlot->endTime,
            $tenantId,
            $excludeId,
        );

        foreach ($classConflicts as $conflicting) {
            $conflicts[] = new ScheduleConflict(
                type: 'class',
                conflictingSlot: $conflicting,
                description: "La classe a déjà un cours le {$conflicting->dayOfWeek->label()} de {$conflicting->timeSlot->startTime} à {$conflicting->timeSlot->endTime}.",
            );
        }

        $teacherConflicts = $this->repository->findOverlappingForTeacher(
            $slot->teacherId,
            $slot->dayOfWeek,
            $slot->timeSlot->startTime,
            $slot->timeSlot->endTime,
            $tenantId,
            $excludeId,
        );

        foreach ($teacherConflicts as $conflicting) {
            $conflicts[] = new ScheduleConflict(
                type: 'teacher',
                conflictingSlot: $conflicting,
                description: "L'enseignant est déjà occupé le {$conflicting->dayOfWeek->label()} de {$conflicting->timeSlot->startTime} à {$conflicting->timeSlot->endTime}.",
            );
        }

        if ($slot->room !== null) {
            $roomConflicts = $this->repository->findOverlappingForRoom(
                $slot->room,
                $slot->dayOfWeek,
                $slot->timeSlot->startTime,
                $slot->timeSlot->endTime,
                $tenantId,
                $excludeId,
            );

            foreach ($roomConflicts as $conflicting) {
                $conflicts[] = new ScheduleConflict(
                    type: 'room',
                    conflictingSlot: $conflicting,
                    description: "La salle {$slot->room} est déjà occupée le {$conflicting->dayOfWeek->label()} de {$conflicting->timeSlot->startTime} à {$conflicting->timeSlot->endTime}.",
                );
            }
        }

        return $conflicts;
    }
}
