<?php

namespace Myvetshop\Module\Clinique\Accounting\Export\Exporter;

use Myvetshop\Module\Clinique\Accounting\Export\Exporter\PostProcess\ExportPostProcessorInterface;
use Myvetshop\Module\Clinique\Accounting\Export\Exporter\Provider\LineProviderInterface;
use Myvetshop\Module\Clinique\Accounting\Export\Model\ExportLine;
use Myvetshop\Module\Clinique\Accounting\Export\Model\SimpleAccountingLineInterface;

/**
 * @template DocType of \OrderInvoice|\OrderSlip
 *
 * @implements DocumentExporterInterface<DocType>
 */
abstract class AbstractDocumentExporter implements DocumentExporterInterface
{
    /**
     * @var list<LineProviderInterface<DocType>>
     */
    protected array $providers;

    /**
     * @var ExportPostProcessorInterface[]
     */
    protected array $postProcessors;

    protected string $entitled;

    /**
     * @param DocType $document
     */
    abstract protected function getDocumentDate($document): \DateTimeImmutable;

    /**
     * @param DocType $document
     */
    abstract protected function getDocumentReference($document, \Order $order): string;

    /**
     * @param DocType $document
     */
    public function export($document, \Order $order): array
    {
        $documentDate = $this->getDocumentDate($document);
        $documentReference = $this->getDocumentReference($document, $order);

        /**
         * @var list<SimpleAccountingLineInterface> $simpleLines
         */
        $simpleLines = \call_user_func_array(
            'array_merge',
            \array_map(
                fn ($provider) => $provider->getAccountingLines($document, $order),
                $this->providers
            )
        );

        $lines = \array_map(
            fn (SimpleAccountingLineInterface $line) => ExportLine::createFromSimpleLine(
                $line,
                $documentDate,
                $documentReference,
                $this->entitled
            ),
            $simpleLines
        );

        foreach ($this->postProcessors as $processor) {
            $lines = $processor->postProcess($lines);
        }

        return $lines;
    }
}
