<?php

declare(strict_types=1);

/*
 * Chill is a software for social workers
 *
 * For the full copyright and license information, please view
 * the LICENSE file that was distributed with this source code.
 */

namespace Chill\MainBundle\Security\Authorization;

use Chill\MainBundle\Entity\Notification;
use Chill\MainBundle\Entity\NotificationComment;
use Chill\MainBundle\Entity\User;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;

final class NotificationVoter extends Voter
{
    /**
     * Allow to add a comment on a notification.
     *
     * May apply on both @see{NotificationComment::class} and @see{Notification::class}.
     */
    public const COMMENT_ADD = 'CHILL_MAIN_NOTIFICATION_COMMENT_ADD';

    public const COMMENT_EDIT = 'CHILL_MAIN_NOTIFICATION_COMMENT_EDIT';

    public const NOTIFICATION_SEE = 'CHILL_MAIN_NOTIFICATION_SEE';

    public const NOTIFICATION_TOGGLE_READ_STATUS = 'CHILL_MAIIN_NOTIFICATION_TOGGLE_READ_STATUS';

    public const NOTIFICATION_UPDATE = 'CHILL_MAIN_NOTIFICATION_UPDATE';

    protected function supports($attribute, $subject): bool
    {
        return $subject instanceof Notification || $subject instanceof NotificationComment;
    }

    /**
     * @param string $attribute
     */
    protected function voteOnAttribute($attribute, $subject, TokenInterface $token): bool
    {
        $user = $token->getUser();

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

        if ($subject instanceof Notification) {
            return match ($attribute) {
                self::COMMENT_ADD => false === $subject->isSystem() && (
                    $subject->getAddressees()->contains($user) || $subject->getSender() === $user
                ),
                self::NOTIFICATION_SEE, self::NOTIFICATION_TOGGLE_READ_STATUS => $subject->getSender() === $user || $subject->getAddressees()->contains($user),
                self::NOTIFICATION_UPDATE => $subject->getSender() === $user && false === $subject->isSystem(),
                default => throw new \UnexpectedValueException("this subject {$attribute} is not implemented"),
            };
        } elseif ($subject instanceof NotificationComment) {
            return match ($attribute) {
                self::COMMENT_ADD => false === $subject->getNotification()->isSystem() && (
                    $subject->getNotification()->getAddressees()->contains($user) || $subject->getNotification()->getSender() === $user
                ),
                self::COMMENT_EDIT => $subject->getCreatedBy() === $user && false === $subject->getNotification()->isSystem(),
                default => throw new \UnexpectedValueException("this subject {$attribute} is not implemented"),
            };
        }

        throw new \UnexpectedValueException();
    }
}
