<?php

declare(strict_types=1);

/*
 * This file is part of the Ferienpass package.
 *
 * (c) Richard Henkenjohann <richard@ferienpass.online>
 *
 * For more information visit the project website <https://ferienpass.online>
 * or the documentation under <https://docs.ferienpass.online>.
 */

namespace Ferienpass\CoreBundle\EventListener\Filesystem;

use Contao\CoreBundle\File\Metadata;
use Contao\CoreBundle\Filesystem\Dbafs\AbstractDbafsMetadataEvent;
use Contao\CoreBundle\Filesystem\Dbafs\RetrieveDbafsMetadataEvent;
use Contao\CoreBundle\Filesystem\Dbafs\StoreDbafsMetadataEvent;
use Contao\Image\ImportantPart;
use Doctrine\ORM\EntityManagerInterface;
use Ferienpass\CoreBundle\Entity\DbafsMedia;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Uid\Uuid;

class DbafsMetadataSubscriber implements EventSubscriberInterface
{
    public function __construct(private readonly EntityManagerInterface $entityManager)
    {
    }

    public function enhanceMetadata(RetrieveDbafsMetadataEvent $event): void
    {
        if (!$this->supports($event)) {
            return;
        }

        $row = $event->getRow();

        $model = $this->entityManager->getReference('Ferienpass\CoreBundle\Entity\\'.$event->getTable(), Uuid::fromString($row['uuid']));
        $event->set('model', $model);

        // Add important part
        if (
            'DbafsMedia' === $event->getTable()
            && null !== ($x = $row['importantPartX'] ?? null)
            && null !== ($y = $row['importantPartY'] ?? null)
            && null !== ($width = $row['importantPartWidth'] ?? null)
            && null !== ($height = $row['importantPartHeight'] ?? null)
        ) {
            $x = (float) $x;
            $y = (float) $y;
            $width = (float) $width;
            $height = (float) $height;

            if (
                $x >= 0 && $x <= 1
                && $y >= 0 && $y <= 1
                && $width >= 0 && $width <= 1
                && $height >= 0 && $height <= 1
                && ($x + $width) <= 1
                && ($y + $height) <= 1
            ) {
                $event->set('importantPart', new ImportantPart($x, $y, $width, $height));
            }
        }

        if ($model instanceof DbafsMedia) {
            $metadata = new Metadata([
                Metadata::VALUE_UUID => $event->getUuid()->toRfc4122(),
                'alt' => $model->getAlt(),
                'creator' => $model->getCreator(),
            ]);
        } else {
            $metadata = new Metadata([
                Metadata::VALUE_UUID => $event->getUuid()->toRfc4122(),
            ]);
        }

        $event->set('metadata', $metadata);
    }

    public function normalizeMetadata(StoreDbafsMetadataEvent $event): void
    {
        if (!$this->supports($event)) {
            return;
        }

        $extraMetadata = $event->getExtraMetadata();
        $importantPart = $extraMetadata['importantPart'] ?? null;

        if ($importantPart instanceof ImportantPart) {
            $event->set('importantPartX', $importantPart->getX());
            $event->set('importantPartY', $importantPart->getY());
            $event->set('importantPartWidth', $importantPart->getWidth());
            $event->set('importantPartHeight', $importantPart->getHeight());
        }
    }

    public static function getSubscribedEvents(): array
    {
        return [
            RetrieveDbafsMetadataEvent::class => ['enhanceMetadata'],
            StoreDbafsMetadataEvent::class => ['normalizeMetadata'],
        ];
    }

    private function supports(AbstractDbafsMetadataEvent $event): bool
    {
        return \in_array($event->getTable(), ['DbafsMedia', 'DbafsAttachment', 'DbafsLogo'], true);
    }
}
