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

/**
 * @Shopware\noEncryption
 */

namespace Shopware\CustomModels\ViisonShippingCommon\Shipment;

use Doctrine\ORM\Mapping as ORM;
use Shopware\Components\Model\ModelEntity;
use Shopware\Plugins\ViisonCommon\Classes\Util\Doctrine as DoctrineUtil;
use \InvalidArgumentException;
use \LogicException;
use Shopware\Plugins\ViisonCommon\Classes\Util\Util;
use Shopware\Plugins\ViisonCommon\Components\FileStorage\FileStorage;

/**
 * @ORM\MappedSuperclass
 *
 * Note: Every adapter needs to specify the ORM\Table and ORM\Entity annotations in their subclasses of this model:
 *
 *       ORM\Entity(repositoryClass="Shopware\CustomModels\ADAPTER_NAME\Shipment\Repository")
 *       ORM\Table(name="s_plugin_ADAPTER_NAME_shipment_documents")
 */
abstract class Document extends ModelEntity
{
    /**
     * Document types
     */
    const DOCUMENT_TYPE_SHIPPING_LABEL = 'label';
    const DOCUMENT_TYPE_RETURN_LABEL = 'returnLabel';
    const DOCUMENT_TYPE_EXPORT_DOCUMENT = 'exportDocument';

    /**
     * Returns the file prefix of the Adapter used for saving the document (dhl, german_post, ...).
     *
     * @return string
     */
    abstract public function getFilePrefix();

    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer", nullable=false)
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    protected $id;

    /**
     * @var int
     *
     * @ORM\Column(name="shipmentId", type="integer", nullable=false)
     */
    protected $shipmentId;

    /**
     * OWNING SIDE
     *
     * @var Shipment
     *
     * Note: This definition has no annotations, because they have to be defined in the subclasses. Re-implement this
     *       property again in your subclass with the following annotation (replace ADAPTER_NAME):
     *
     *       ORM\ManyToOne(targetEntity="Shopware\CustomModels\ADAPTER_NAME\Shipment\Shipment", inversedBy="documents")
     *       ORM\JoinColumn(name="shipmentId", referencedColumnName="id", onDelete="CASCADE")
     */
    protected $shipment;

    /**
     * @var string
     *
     * @ORM\Column(name="labelType", type="string", nullable=false)
     */
    protected $type;

    /**
     * @var string
     *
     * @ORM\Column(name="pageSize", type="string", nullable=true)
     */
    protected $pageSize;

    /**
     * An identifier for the document that is unique system wide (and especially unique above all shipping providers)
     *
     * @var string
     *
     * @ORM\Column(name="guid", type="string", nullable=false, unique=true)
     */
    protected $guid;

    /**
     */
    public function __construct()
    {
        $this->guid = Util::createGUID();
    }

    /**
     * @return int
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * @return Shipment
     */
    public function getShipment()
    {
        return $this->shipment;
    }

    /**
     * @param Shipment $shipment
     * @throws InvalidArgumentException
     */
    public function setShipment(Shipment $shipment)
    {
        // Make sure the passed shipment is part of the same namespace as this document
        if (!DoctrineUtil::customModelsShareNamespace($shipment, $this)) {
            throw new InvalidArgumentException(
                sprintf('The namespace of the provided $shipment (%s) must match the namespace of $this document (%s).', get_class($shipment), get_class($this))
            );
        }

        $this->shipment = $shipment;
    }

    /**
     * @return string
     */
    public function getType()
    {
        return $this->type;
    }

    /**
     * @param string $type
     */
    public function setType($type)
    {
        $this->type = $type;
    }

    /**
     * @return string|null
     */
    public function getPageSize()
    {
        return $this->pageSize;
    }

    /**
     * @param string|null $pageSize
     */
    public function setPageSize($pageSize)
    {
        $this->pageSize = $pageSize;
    }

    /**
     * Returns the path to the PDF file associated with this document.
     *
     * @deprecated Use `getDocumentFileName()` instead.
     *
     * @return string
     * @throws LogicException
     */
    public function getDocumentPath()
    {
        if (!$this->getId()) {
            throw new LogicException('Document entity must be persisted before the document path can be returned');
        }

        $documentsPath = Shopware()->Container()->getParameter('kernel.root_dir') . '/files/documents/';
        $fileName = $this->getFilePrefix() . '-' . $this->getId() . '-' . $this->getType() . '.pdf';

        return $documentsPath . $fileName;
    }

    /**
     * Returns the file name to the PDF file associated with this document.
     *
     * @return string
     * @throws LogicException
     */
    public function getDocumentFileName()
    {
        if (!$this->getId()) {
            throw new LogicException('Document entity must be persisted before the document path can be returned');
        }

        return $this->getFilePrefix() . '-' . $this->getId() . '-' . $this->getType() . '.pdf';
    }

    /**
     * Returns the contents of the PDF files associated with this document, if it exists.
     *
     * @throws \Exception
     * @return string
     */
    public function getDocumentAsPDF()
    {
        /** @var FileStorage $fileStorageService */
        $fileStorageService = Shopware()->Container()->get('viison_common.document_file_storage_service');
        $documentFileName = $this->getDocumentFileName();
        if (!$fileStorageService->doesFileExist($documentFileName)) {
            throw new \Exception('File ' . $documentFileName . ' not found.');
        }

        return $fileStorageService->readFileContents($documentFileName);
    }

    /**
     * Override this, when there are different document types (or page formats)
     *
     * @return int
     */
    public function getDocumentTypeId()
    {
        return 1;
    }

    /**
     * @return string
     */
    public function getGuid()
    {
        return $this->guid;
    }

    /**
     * @param string $guid
     */
    public function setGuid($guid)
    {
        $this->guid = $guid;
    }
}
