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

use Doctrine\ORM\EntityManager;
use \Exception;
use \LogicException;
use Shopware\Plugins\ViisonCommon\Components\FileStorage\FileStorage;
use \Zend_Db_Table;
use Shopware\Components\DependencyInjection\Container;
use Shopware\Plugins\ViisonCommon\Classes\Util\Util as ShopwareCommonUtil;

class OrderDocumentCollectorService
{
    /**
     * @var \Shopware\Components\Model\ModelManager
     */
    protected $entityManager;

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

    /**
     * OrderDocumentCollectorService constructor.
     *
     * @param EntityManager $entityManager
     * @param FileStorage $fileStorageService
     */
    public function __construct(
        EntityManager $entityManager,
        FileStorage $fileStorageService
    ) {
        $this->entityManager = $entityManager;
        $this->fileStorageService = $fileStorageService;
    }

    /**
     * @param $pluginInfo
     * @param string $orderId
     * @param string $documentType
     * @return string
     * @throws Exception
     */
    public function getMergedDocumentPDFs($pluginInfo, $orderId, $documentType)
    {
        $entityName = $pluginInfo->getShipmentModelName();
        if ($entityName !== null) {
            $labelsAsPdf = $this->getDocumentPDFsViaShipmentEntity(
                $entityName,
                $orderId,
                $documentType
            );
        } else {
            $labelsAsPdf = $this->getDocumentPDFsViaOrderTable(
                $pluginInfo->getOrderTableName(),
                $orderId,
                $documentType,
                $pluginInfo->getFilePrefix()
            );
        }

        return ShopwareCommonUtil::mergePdfDocumentContents($labelsAsPdf, 'AUTO');
    }

    /**
     * @param string $shipmentEntityName
     * @param int $orderId
     * @param string $documentType
     * @return array
     * @throws Exception
     */
    protected function getDocumentPDFsViaShipmentEntity($shipmentEntityName, $orderId, $documentType)
    {
        /** @var Shipment [] $shipments */
        $shipments = $this->entityManager->getRepository($shipmentEntityName)->findBy(array(
            'orderId' => $orderId,
        ));

        if (count($shipments) === 0) {
            self::throwNoLabelException();
        }

        $documentsAsPdf = array();
        foreach ($shipments as $shipment) {
            foreach ($shipment->getDocuments() as $document) {
                /** @var Document $document */
                if ($document->getType() === $documentType) {
                    $documentsAsPdf[] = $document->getDocumentAsPDF();
                }
            }
        }

        return $documentsAsPdf;
    }

    /**
     * @param string $orderTableName
     * @param int $orderId
     * @param string $documentType
     * @param string $documentPrefix
     * @return array
     * @throws Exception
     */
    protected function getDocumentPDFsViaOrderTable($orderTableName, $orderId, $documentType, $documentPrefix)
    {
        $shippingAdapterOrderTable = new Zend_Db_Table($orderTableName);

        $shippingLabelUrls = $shippingAdapterOrderTable->fetchAll(
            $shippingAdapterOrderTable->select()
                ->from($shippingAdapterOrderTable, array('url'))
                ->where('orderId = ?', $orderId)
        )->toArray();

        if (count($shippingLabelUrls) === 0) {
            self::throwNoLabelException();
        }

        $documentsAsPdf = array();
        foreach ($shippingLabelUrls as $shippingLabelUrl) {
            $documentAsPdfOrNull = $this->getDocumentAsPDFOrNull(
                $this->getIdentifierFromDocumentUrl($shippingLabelUrl['url']),
                $documentType,
                $documentPrefix
            );

            // Ignore if null is returned
            if ($documentAsPdfOrNull !== null) {
                $documentsAsPdf[] = $documentAsPdfOrNull;
            }
        }

        return $documentsAsPdf;
    }

    /**
     * @throws Exception
     */
    protected function throwNoLabelException()
    {
        throw new Exception('No shipping labels under this order.');
    }

    /**
     * Tries to find the requested document in the downloaded documents directory
     * and just returns it or null if not found.
     *
     * @param string $identifier
     * @param string $documentType
     * @param string $documentPrefix
     * @return null|string
     */
    protected function getDocumentAsPDFOrNull($identifier, $documentType, $documentPrefix)
    {
        $documentPath = $this->getDocumentFileName($identifier, $documentType, $documentPrefix);
        if (!$this->fileStorageService->doesFileExist($documentPath)) {
            return null;
        }

        // The document is already downloaded, so just open and return it
        return $this->fileStorageService->readFileContents($documentPath);
    }

    /**
     * Constructs a path to a document file using the given identifier and type.
     *
     * @param string $documentIdentifier The tracking code used to construct the path.
     * @param string $docType The document type used to construct the path.
     * @param string $documentPrefix The prefix used for the document creation.
     * @return string The file path, where the document is stored.
     */
    protected function getDocumentFileName($documentIdentifier, $docType, $documentPrefix)
    {
        return $documentPrefix . '-' . $documentIdentifier . '-' . $docType . '.pdf';
    }

    /**
     * Regex matcher, extract the Identifier from the given URL.
     *
     * NOTE: Identifier can be Tracking Code, ...
     *
     * @param string $url
     * @return string
     */
    protected function getIdentifierFromDocumentUrl($url)
    {
        $matches = array();
        preg_match('/.*:(.*?)$/', $url, $matches);

        return $matches[1];
    }
}
