<?php
/**
 * Copyright since 2025 InPost S.A.
 *
 * For the full license information, please view the LICENSE file bundled with the module.
 *
 * @author InPost S.A.
 * @copyright since 2025 InPost S.A.
 * @license MIT
 */

declare(strict_types=1);

namespace InPost\International\File;

use ZipStream\Option\Archive;
use ZipStream\ZipStream;

if (!defined('_PS_VERSION_')) {
    exit;
}

final class Base64EncodedFilesArchive implements StreamableInterface
{
    /**
     * @var iterable<string, string>
     */
    private $files;

    /**
     * @var string
     */
    private $filename;

    /**
     * @param iterable<string, string> $files base64 content by file name
     */
    public function __construct(iterable $files, string $filename = 'archive.zip')
    {
        $this->files = $files;
        $this->filename = $filename;
    }

    public function stream(): void
    {
        $zip = $this->createZipStream();

        foreach ($this->files as $filename => $content) {
            $stream = fopen('php://temporary', 'rb+');

            try {
                stream_filter_append($stream, 'convert.base64-decode', STREAM_FILTER_WRITE);
                fwrite($stream, $content);
                fseek($stream, 0);

                $zip->addFileFromStream($filename, $stream);
            } finally {
                fclose($stream);
            }
        }

        $zip->finish();
    }

    public function getContentType(): string
    {
        return 'application/zip';
    }

    public function getFilename(): string
    {
        return $this->filename;
    }

    private function createZipStream(): ZipStream
    {
        if (self::isZipStreamV3()) {
            return new ZipStream(...[
                'sendHttpHeaders' => false,
                'flushOutput' => true,
            ]);
        }

        $options = new Archive();
        $options->setFlushOutput(true);

        return new ZipStream(null, $options);
    }

    private static function isZipStreamV3(): bool
    {
        $class = new \ReflectionClass(ZipStream::class);
        $constructor = $class->getConstructor();

        return 2 < $constructor->getNumberOfParameters();
    }
}
