<?php
// Copyright (c) Pickware GmbH. All rights reserved.
// This file is part of software that is released under a proprietary license.
// You must not copy, modify, distribute, make publicly available, or execute
// its contents or parts thereof without express permission by the copyright
// holder, unless otherwise permitted by law.

namespace Shopware\Plugins\ViisonPickwareCommon\Components;

use Enlight_Event_EventManager;
use Enlight_Event_Handler_Default;
use Enlight_Hook_HookArgs;
use ReflectionObject;
use Shopware\Components\Model\ModelManager;
use Shopware\Models\Order\Document\Document as OrderDocument;
use Shopware\Plugins\ViisonCommon\Classes\Util\Document as DocumentUtil;
use Shopware\Plugins\ViisonCommon\Classes\Util\Util as ViisonCommonUtil;
use Shopware\Plugins\ViisonCommon\Components\FileStorage\FileStorage;

/**
 * Note: Dynamically registering hook listeners with the event manager only works if the respective hook proxy is
 * guaranteed to contain overrides for the hooked methods. For the listeners created by this service this is facilitated
 * by registering {@link Shopware\Plugins\ViisonPickwareCommon\Subscribers\Components\DocumentComponentSubscriber},
 * which is done alongside registering all other ViisonPickwareCommon subscribers.
 */
class DocumentComponentListenerService
{
    /**
     * @var ModelManager
     */
    private $entityManager;

    /**
     * @var Enlight_Event_EventManager
     */
    private $eventManager;

    /**
     * @var FileStorage
     */
    private $documentFileStorage;

    /**
     * @param ModelManager $entityManager
     * @param Enlight_Event_EventManager $eventManager
     * @param FileStorage $documentFileStorage
     */
    public function __construct(
        ModelManager $entityManager,
        Enlight_Event_EventManager $eventManager,
        FileStorage $documentFileStorage
    ) {
        $this->entityManager = $entityManager;
        $this->eventManager = $eventManager;
        $this->documentFileStorage = $documentFileStorage;
    }

    /**
     * Registers a one-off (after) hook handler on {@link Shopware_Components_Document::render()} that appends the file
     * pointed to by the given `$filePath` to the created document PDF file.
     *
     * @param string $filePath
     */
    public function appendFileToNextRenderedDocument($filePath)
    {
        $listener = null;
        $listener = new Enlight_Event_Handler_Default(
            'Shopware_Components_Document::render::after',
            function (Enlight_Hook_HookArgs $args) use (&$listener, $filePath) {
                // Remove this listener to ensure it is only called once
                $this->eventManager->removeListener($listener);

                $documentComponent = $args->getSubject();

                // Ensure that the document was rendered to disk
                $reflectionObject = new ReflectionObject($documentComponent);
                $rendererProperty = $reflectionObject->getProperty('_renderer');
                $rendererProperty->setAccessible(true);
                $renderer = $rendererProperty->getValue($documentComponent);
                if ($renderer !== 'pdf') {
                    return;
                }

                // Find the created document
                $documentRowIdProperty = $reflectionObject->getProperty('_documentRowID');
                $documentRowIdProperty->setAccessible(true);
                $documentId = $documentRowIdProperty->getValue($documentComponent);
                $document = $this->entityManager->find(OrderDocument::class, $documentId);
                if (!$document) {
                    return;
                }

                // Append the file to the rendered document file
                $mergedDocumentContent = ViisonCommonUtil::mergePdfDocumentFiles(
                    [
                        DocumentUtil::getDocumentPath($document),
                        $filePath,
                    ],
                    'AUTO'
                );

                /** @var FileStorage $documentFileStorage */
                $this->documentFileStorage->writeFileContents(
                    DocumentUtil::getDocumentFileName($document),
                    $mergedDocumentContent
                );
            },
            // Use a very low/ early position to allow other hooks to get the document incl. the appended file
            -100000
        );
        $this->eventManager->registerListener($listener);
    }
}
