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

use Contao\CoreBundle\Filesystem\VirtualFilesystemInterface;
use Doctrine\ORM\EntityManagerInterface;
use Ferienpass\CoreBundle\Entity\DbafsMedia;
use Ferienpass\CoreBundle\Entity\Offer\OfferInterface;
use Ferienpass\CoreBundle\Entity\User;
use Ferienpass\CoreBundle\Message\GenerateImage;
use Ferienpass\CoreBundle\Message\GeneratePrompt;
use Ferienpass\CoreBundle\Repository\OfferRepositoryInterface;
use Psr\Cache\CacheItemPoolInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Messenger\MessageBusInterface;
use Symfony\Component\String\Slugger\SluggerInterface;
use Symfony\Component\Uid\Uuid;
use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
use Symfony\UX\LiveComponent\Attribute\LiveAction;
use Symfony\UX\LiveComponent\Attribute\LiveProp;
use Symfony\UX\LiveComponent\ComponentToolsTrait;
use Symfony\UX\LiveComponent\DefaultActionTrait;

#[AsLiveComponent(template: '@FerienpassAdmin/components/Offer/ImageGenerator.html.twig', route: 'live_component_admin')]
class ImageGenerator extends AbstractController
{
    use ComponentToolsTrait;
    use DefaultActionTrait;

    #[LiveProp]
    public ?int $offerId = null;

    #[LiveProp(writable: true)]
    public string $prompt = '';

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

    #[LiveProp]
    public bool $isGeneratingPrompt = false;

    #[LiveProp]
    public bool $isGeneratingImage = false;

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

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

    public function __construct(
        private readonly OfferRepositoryInterface $offerRepository,
        private readonly EntityManagerInterface $entityManager,
        private readonly MessageBusInterface $commandBus,
        private readonly CacheItemPoolInterface $cache,
        private readonly SluggerInterface $slugger
    ) {
    }

    #[LiveAction]
    public function generatePrompt(): void
    {
        $offer = $this->offerRepository->find($this->offerId);
        if (!$offer) {
            return;
        }

        $this->isGeneratingPrompt = true;
        $this->promptJobId = Uuid::v7()->toRfc4122();

        $context = \sprintf("Titel: %s\nBeschreibung: %s", $offer->getName(), $offer->getDescription());

        $this->commandBus->dispatch(new GeneratePrompt($context, $this->promptJobId));
    }

    #[LiveAction]
    public function generateImage(): void
    {
        if (empty($this->prompt)) {
            return;
        }

        $this->isGeneratingImage = true;
        $this->jobId = Uuid::v7()->toRfc4122();

        $user = $this->getUser();
        $userId = $user instanceof User ? $user->getUuid() : null;

        $offer = $this->offerRepository->find($this->offerId);
        $offerUuid = $offer?->getUuid();

        $this->commandBus->dispatch(new GenerateImage(
            $this->prompt,
            $this->jobId,
            $offerUuid?->toRfc4122(),
            $userId?->toRfc4122()
        ));
    }

    #[LiveAction]
    public function checkStatus(): void
    {
        if ($this->promptJobId && $this->isGeneratingPrompt) {
            $item = $this->cache->getItem('ai_prompt_'.$this->promptJobId);
            if ($item->isHit()) {
                $this->prompt = $item->get();
                $this->isGeneratingPrompt = false;
                $this->promptJobId = null;
            }
        }

        if ($this->jobId && $this->isGeneratingImage) {
            $item = $this->cache->getItem('ai_image_'.$this->jobId);
            if ($item->isHit()) {
                $result = $item->get();
                $this->generatedImageUrl = $result['base64'];
                $this->isGeneratingImage = false;
            }
        }
    }

    #[LiveAction]
    public function confirmImage(VirtualFilesystemInterface $mediaStorage): void
    {
        if (!$this->generatedImageUrl) {
            return;
        }

        /** @var OfferInterface $offer */
        $offer = $this->offerRepository->find($this->offerId);
        if (!$offer) {
            return;
        }

        $content = base64_decode($this->generatedImageUrl, true);

        $safeFilename = $this->slugger->slug($offer->getName());
        $fileName = strtolower($safeFilename->toString()).'-'.uniqid().'.jpg';

        $mediaStorage->write($fileName, $content);

        $fsUuid = $mediaStorage->get($fileName)?->getUuid();

        $media = $this->entityManager->getReference(DbafsMedia::class, $fsUuid);
        $media->setCreator('KI-generiert');
        $media->setUploadedBy($this->getUser());
        $offer->addMedia($media);

        $this->entityManager->flush();

        $this->emitUp('imageGenerated', [
            'uuid' => $fsUuid->toRfc4122(),
        ]);

        $this->reset();
    }

    private function reset(): void
    {
        $this->generatedImageUrl = null;
        $this->prompt = '';
    }
}
