<?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\Controller\Page;

use Contao\CoreBundle\Controller\AbstractController;
use Contao\CoreBundle\Exception\PageNotFoundException;
use Ferienpass\CoreBundle\Export\Offer\OffersExportInterface;
use Ferienpass\CoreBundle\Repository\OfferRepositoryInterface;
use FOS\HttpCacheBundle\Http\SymfonyResponseTagger;
use Symfony\Component\DependencyInjection\Attribute\TaggedLocator;
use Symfony\Component\DependencyInjection\ServiceLocator;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
use Symfony\Component\HttpFoundation\StreamedResponse;
use Symfony\Component\Routing\Attribute\Route;

#[Route(path: '/angebote/{edition}/{id}-{!name}.{!_format}', name: 'admin_print_proof', requirements: ['id' => '\d+'], defaults: ['name' => 'druck', 'format' => 'pdf'])]
final class PrintSheetProofController extends AbstractController
{
    public function __construct(#[TaggedLocator(OffersExportInterface::class, indexAttribute: 'name', defaultIndexMethod: 'getName')] private readonly ServiceLocator $exports)
    {
    }

    public function __invoke(int $id, string $name, string $_format, Request $request, OfferRepositoryInterface $repository, SymfonyResponseTagger $responseTagger): Response
    {
        // Only "pdf" is generated. Image extensions (png/jpg/jpeg) collide with the
        // Varnish strip-and-pass rule (cookie stripped behind the cache), so reject them.
        if ('pdf' !== $_format) {
            throw new PageNotFoundException('Format not supported: '.$_format);
        }

        $exporterName = $name.'.pdf';
        if (!$this->exports->has($exporterName)) {
            throw new PageNotFoundException('No print template');
        }

        if (null === $offer = $repository->find($id)) {
            return new Response('Item not found', Response::HTTP_NOT_FOUND);
        }

        $responseTagger->addTags([$offer->getUuid()]);

        /** @var OffersExportInterface $exporter */
        $exporter = $this->exports->get($exporterName);
        $pdfStream = $exporter->generate([$offer], stream: true);

        $contentDisposition = $request->query->get('dl')
            ? ResponseHeaderBag::DISPOSITION_ATTACHMENT
            : ResponseHeaderBag::DISPOSITION_INLINE;

        $downloadName = 'Korrekturabzug '.$offer->getId();

        if ('pdf' === $_format) {
            $response = new StreamedResponse(
                static function () use ($pdfStream) {
                    $outputStream = fopen('php://output', 'w');

                    stream_copy_to_stream($pdfStream, $outputStream);
                }
            );

            $response->headers->add([
                'Content-Security-Policy' => "frame-ancestors 'self'",
                'Content-Type' => 'application/pdf',
                'Content-Transfer-Encoding' => 'binary',
                'Content-Length' => (string) fstat($pdfStream)['size'],
                'Content-Disposition' => $response->headers->makeDisposition($contentDisposition, $downloadName.'.pdf'),
            ]);

            return $response;
        }

        throw new \Exception('This code should not be reached');
    }
}
