<?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;

use Contao\CoreBundle\Filesystem\VirtualFilesystemInterface;
use Contao\CoreBundle\Framework\ContaoFramework;
use Doctrine\ORM\EntityManagerInterface;
use Ferienpass\AdminBundle\Dto\OrganizationDataDto;
use Ferienpass\AdminBundle\Message\HostInvited;
use Ferienpass\AdminBundle\Service\FileUploader;
use Ferienpass\CoreBundle\Entity\DbafsLogo;
use Ferienpass\CoreBundle\Entity\Host;
use Ferienpass\CoreBundle\Entity\User;
use Ferienpass\CoreBundle\Session\Flash;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Messenger\MessageBusInterface;
use Symfony\Component\Security\Http\Attribute\CurrentUser;
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\LiveArg;
use Symfony\UX\LiveComponent\Attribute\LiveProp;
use Symfony\UX\LiveComponent\DefaultActionTrait;
use Symfony\UX\LiveComponent\ValidatableComponentTrait;

#[AsLiveComponent(route: 'live_component_admin')]
final class OrganizationData extends AbstractController
{
    use DefaultActionTrait;
    use ValidatableComponentTrait;

    #[LiveProp]
    public Host $host;

    #[LiveProp(writable: ['name', 'phone', 'street', 'postalCode', 'city', 'country', 'email', 'website', 'mobile', 'fax', 'text'])]
    #[Assert\Valid]
    public OrganizationDataDto $dto;

    #[LiveProp(writable: true)]
    #[Assert\Email]
    public string $inviteeEmail = '';

    #[LiveProp]
    public ?string $isEditing = null;

    #[LiveProp]
    public bool $uploadLogo = false;

    #[LiveProp]
    public bool $addMember = false;

    public ?string $inviteConfirmation = null;

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

    public function mount(Host $host): void
    {
        $this->host = $host;
        $this->dto = new OrganizationDataDto();
        $this->dto->fromEntity($host);
    }

    #[LiveAction]
    public function edit(#[LiveArg] string $property): void
    {
        $this->isEditing = $property;
    }

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

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

    #[LiveAction]
    public function save(EntityManagerInterface $entityManager, Flash $flash): void
    {
        $this->validate();

        $this->isEditing = null;

        $flash->addConfirmation(text: 'Daten gespeichert');

        $this->dto->toEntity($this->host);

        $entityManager->flush();
    }

    #[LiveAction]
    public function upload(Request $request, EntityManagerInterface $entityManager, Flash $flash, VirtualFilesystemInterface $logosStorage, ValidatorInterface $validator)
    {
        $file = $request->files->get('logo');
        if (null === $file) {
            return;
        }

        // This LiveAction bypasses the Symfony form (and therefore its File
        // constraints), so the uploaded logo MUST be validated explicitly here.
        // SVG is intentionally NOT accepted: it can carry inline <script>, which
        // would be a stored-XSS vector once the logo is served to other users.
        $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->host->setLogo($entityManager->getReference(DbafsLogo::class, $uuid));

        $flash->addConfirmation(text: 'Daten gespeichert');
        $entityManager->flush();

        $this->uploadLogo = false;
    }

    #[LiveAction]
    public function invite(#[CurrentUser] User $user, MessageBusInterface $eventBus): void
    {
        $this->validateField('inviteeEmail');

        $eventBus->dispatch(new HostInvited($this->inviteeEmail, $this->host->getId(), $user->getId()));

        $this->addMember = false;
        $this->inviteConfirmation = \sprintf('Die Einladungs-E-Mail wurde an %s verschickt.', $this->inviteeEmail);
    }
}
