<?php

declare(strict_types=1);

namespace App\Service\School;

use App\Entity\Ecole;
use App\Entity\User;
use Symfony\Bundle\SecurityBundle\Security;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;

final class SchoolContext
{
    public function __construct(private readonly Security $security)
    {
    }

    public function getUser(): User
    {
        $user = $this->security->getUser();

        if (!$user instanceof User) {
            throw new AccessDeniedException('Vous devez être connecté pour accéder à cet espace.');
        }

        return $user;
    }

    public function getEcole(): Ecole
    {
        $ecole = $this->getEcoleOrNull();

        if (!$ecole instanceof Ecole) {
            throw new AccessDeniedException('Aucune madrassa n’est liée à ce compte.');
        }

        return $ecole;
    }

    public function getEcoleOrNull(): ?Ecole
    {
        $user = $this->security->getUser();

        if (!$user instanceof User) {
            return null;
        }

        return $user->getEcole();
    }

    public function isSameSchool(?object $subject): bool
    {
        $currentSchool = $this->getEcole();
        $subjectSchool = $this->resolveSchool($subject);

        if (!$subjectSchool instanceof Ecole) {
            return false;
        }

        if ($currentSchool->getId() !== null && $subjectSchool->getId() !== null) {
            return $currentSchool->getId() === $subjectSchool->getId();
        }

        return $currentSchool === $subjectSchool;
    }

    public function assertSameSchool(?object $subject): void
    {
        if (!$this->isSameSchool($subject)) {
            throw new AccessDeniedException('Ressource non disponible pour cette madrassa.');
        }
    }

    private function resolveSchool(?object $subject): ?Ecole
    {
        if ($subject === null) {
            return null;
        }

        if ($subject instanceof Ecole) {
            return $subject;
        }

        if (is_object($subject) && method_exists($subject, 'getEcole')) {
            $ecole = $subject->getEcole();

            return $ecole instanceof Ecole ? $ecole : null;
        }

        throw new \LogicException(sprintf('Impossible de déterminer la madrassa de "%s".', $subject::class));
    }
}
