<?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\DocStoreBundle\Serializer\Normalizer;

use Chill\DocStoreBundle\AsyncUpload\TempUrlGeneratorInterface;
use Chill\DocStoreBundle\Entity\StoredObject;
use Chill\DocStoreBundle\Security\Authorization\StoredObjectRoleEnum;
use Chill\DocStoreBundle\Security\Guard\JWTDavTokenProviderInterface;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerAwareTrait;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;

/**
 * Class StoredObjectNormalizer.
 *
 * Normalizes a StoredObject entity to an array of data.
 */
final class StoredObjectNormalizer implements NormalizerInterface, NormalizerAwareInterface
{
    use NormalizerAwareTrait;

    /**
     * when added to the groups, a download link is included in the normalization,
     * and no webdav links are generated.
     */
    public const DOWNLOAD_LINK_ONLY = 'read:download-link-only';

    public function __construct(
        private readonly JWTDavTokenProviderInterface $JWTDavTokenProvider,
        private readonly UrlGeneratorInterface $urlGenerator,
        private readonly Security $security,
        private readonly TempUrlGeneratorInterface $tempUrlGenerator,
    ) {}

    public function normalize($object, ?string $format = null, array $context = [])
    {
        /** @var StoredObject $object */
        $datas = [
            'id' => $object->getId(),
            'datas' => $object->getDatas(),
            'prefix' => $object->getPrefix(),
            'title' => $object->getTitle(),
            'uuid' => $object->getUuid()->toString(),
            'status' => $object->getStatus(),
            'createdAt' => $this->normalizer->normalize($object->getCreatedAt(), $format, $context),
            'createdBy' => $this->normalizer->normalize($object->getCreatedBy(), $format, $context),
            'currentVersion' => $this->normalizer->normalize($object->getCurrentVersion(), $format, [...$context, [AbstractNormalizer::GROUPS => 'read']]),
            'totalVersions' => $object->getVersions()->count(),
        ];

        // deprecated property
        $datas['creationDate'] = $datas['createdAt'];

        if (array_key_exists(AbstractNormalizer::GROUPS, $context)) {
            $groupsNormalized = is_array($context[AbstractNormalizer::GROUPS]) ? $context[AbstractNormalizer::GROUPS] : [$context[AbstractNormalizer::GROUPS]];
        } else {
            $groupsNormalized = [];
        }

        if (in_array(self::DOWNLOAD_LINK_ONLY, $groupsNormalized, true)) {
            $datas['_permissions'] = [
                'canSee' => true,
                'canEdit' => false,
            ];
            $datas['_links'] = [
                'downloadLink' => $this->normalizer->normalize($this->tempUrlGenerator->generate('GET', $object->getCurrentVersion()->getFilename(), 180), $format, [AbstractNormalizer::GROUPS => ['read']]),
            ];

            return $datas;
        }

        $canSee = $this->security->isGranted(StoredObjectRoleEnum::SEE->value, $object);
        $canEdit = $this->security->isGranted(StoredObjectRoleEnum::EDIT->value, $object);

        $datas['_permissions'] = [
            'canEdit' => $canEdit,
            'canSee' => $canSee,
        ];

        if ($canSee || $canEdit) {
            $accessToken = $this->JWTDavTokenProvider->createToken(
                $object,
                $canEdit ? StoredObjectRoleEnum::EDIT : StoredObjectRoleEnum::SEE
            );

            $datas['_links'] = [
                'dav_link' => [
                    'href' => $this->urlGenerator->generate(
                        'chill_docstore_dav_document_get',
                        [
                            'uuid' => $object->getUuid(),
                            'access_token' => $accessToken,
                        ],
                        UrlGeneratorInterface::ABSOLUTE_URL,
                    ),
                    'expiration' => $this->JWTDavTokenProvider->getTokenExpiration($accessToken)->getTimestamp(),
                ],
            ];
        }

        return $datas;
    }

    public function supportsNormalization($data, ?string $format = null)
    {
        return $data instanceof StoredObject && 'json' === $format;
    }
}
