<?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\PersonBundle\Privacy;

/*
 * Chill is a software for social workers
 *
 * Copyright (C) 2014-2015, Champs Libres Cooperative SCRLFS,
 * <http://www.champs-libres.coop>, <info@champs-libres.coop>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

use Chill\MainBundle\Entity\User;
use Chill\PersonBundle\Entity\Person;
use Psr\Log\LoggerInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;

final readonly class PrivacyEventSubscriber implements EventSubscriberInterface
{
    /**
     * PrivacyEventSubscriber constructor.
     */
    public function __construct(
        private LoggerInterface $logger,
        private TokenStorageInterface $token,
    ) {}

    public static function getSubscribedEvents()
    {
        return [
            PrivacyEvent::PERSON_PRIVACY_EVENT => [
                ['onPrivacyEvent'],
            ],
            AccompanyingPeriodPrivacyEvent::ACCOMPANYING_PERIOD_PRIVACY_EVENT => [
                ['onAccompanyingPeriodPrivacyEvent'],
            ],
        ];
    }

    public function onAccompanyingPeriodPrivacyEvent(AccompanyingPeriodPrivacyEvent $event)
    {
        $involved = $this->getInvolved();
        $involved['period_id'] = $event->getPeriod()->getId();
        $involved['persons'] = $event->getPeriod()->getPersons()
            ->map(static fn (Person $p) => $p->getId())
            ->toArray();

        $this->logger->notice(
            '[Privacy Event] An accompanying period has been viewed',
            array_merge($involved, $event->getArgs())
        );
    }

    public function onPrivacyEvent(PrivacyEvent $event)
    {
        $persons = [];

        if (true === $event->hasPersons()) {
            foreach ($event->getPersons() as $person) {
                $persons[] = $person->getId();
            }
        }

        $involved = $this->getInvolved();
        $involved['person_id'] = $event->getPerson()->getId();

        if ($event->hasPersons()) {
            $involved['persons'] = \array_map(
                static fn (Person $p) => $p->getId(),
                $event->getPersons()
            );
        }

        $this->logger->notice(
            '[Privacy Event] A Person Folder has been viewed',
            array_merge($involved, $event->getArgs())
        );
    }

    private function getInvolved(): array
    {
        $user = $this->token->getToken()->getUser();

        if ($user instanceof User) {
            return [
                'by_user' => $user->getUserIdentifier(),
                'by_user_id' => $user->getId(),
            ];
        }

        return [
            'by_user' => $user->getUsername(),
            'by_user_id' => $user->getUserIdentifier(),
        ];
    }
}
