<?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\AdminBundle\Components\Settings;

use Contao\CoreBundle\Filesystem\VirtualFilesystemInterface;
use Doctrine\ORM\EntityManagerInterface;
use Ferienpass\AdminBundle\Service\FileUploader;
use Ferienpass\CoreBundle\Entity\DbafsLogo;
use Ferienpass\CoreBundle\Entity\PageConfig;
use Ferienpass\CoreBundle\Session\Flash;
use Ferienpass\CoreBundle\Settings\PageConfigManager;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
use Symfony\UX\LiveComponent\Attribute\LiveAction;
use Symfony\UX\LiveComponent\Attribute\LiveProp;
use Symfony\UX\LiveComponent\DefaultActionTrait;

/**
 * The logo island inside the Systemkonfiguration form. It stays a live
 * component of its own: a file upload does not survive a page-wide form
 * re-render, and the logo saves independently of the settings around it.
 *
 * The markup deliberately contains no <form> — the component sits inside the
 * settings form, and the `files()` live expression reads the file input
 * directly.
 */
#[AsLiveComponent(name: 'Admin:Settings:LogoUpload', template: '@FerienpassAdmin/components/Settings/LogoUpload.html.twig', route: 'live_component_admin')]
final class LogoUpload extends AbstractController
{
    use DefaultActionTrait;

    #[LiveProp]
    public PageConfig $config;

    #[LiveProp]
    public bool $uploadLogo = false;

    public ?string $confirmation = null;

    public function __construct(private readonly FileUploader $fileUploader)
    {
    }

    #[LiveAction]
    public function showUploadLogo(): void
    {
        $this->uploadLogo = true;
    }

    #[LiveAction]
    public function cancelUploadLogo(): void
    {
        $this->uploadLogo = false;
    }

    /**
     * The logo the system e-mails carry. It is stored in the database (not in
     * the repository) so it follows the tenant into a worker rendering a
     * queued mail, where there is no host and no per-tenant template path to
     * derive branding from.
     */
    #[LiveAction]
    public function upload(Request $request, EntityManagerInterface $entityManager, PageConfigManager $pageConfigManager, VirtualFilesystemInterface $logosStorage, ValidatorInterface $validator, Flash $flash): void
    {
        $file = $request->files->get('logo');
        if (null === $file) {
            return;
        }

        // This LiveAction bypasses the Symfony form (and therefore its File
        // constraints), so the upload MUST be validated explicitly here. SVG is
        // intentionally not accepted: it can carry inline <script>, and this
        // logo is served to everyone who opens one of our e-mails.
        $violations = $validator->validate($file, new Assert\Image(
            maxSize: '1024k',
            mimeTypes: ['image/jpeg', 'image/png', 'image/webp'],
            mimeTypesMessage: 'Erlaubte Dateitypen sind: JPG, PNG, WebP',
        ));

        if ($violations->count() > 0) {
            $flash->addError(text: $violations->get(0)->getMessage());

            return;
        }

        $uuid = $this->fileUploader->upload($logosStorage, $file);

        $this->config->setLogo($entityManager->getReference(DbafsLogo::class, $uuid));

        $pageConfigManager->savePageConfig($this->config);

        $this->uploadLogo = false;
        $this->confirmation = 'Logo gespeichert.';
    }

    #[LiveAction]
    public function removeLogo(PageConfigManager $pageConfigManager): void
    {
        $this->config->setLogo(null);

        $pageConfigManager->savePageConfig($this->config);

        $this->confirmation = 'Logo entfernt.';
    }
}
