<?php

namespace NoahVet\Reef\Domain\Http\Multipart;

class MultipartParser implements MultipartParserInterface
{
    public function __construct(
        private readonly HeaderParserInterface $headerParser,
        private readonly PartExtractorInterface $partExtractor,
        private readonly ContentDecoderInterface $contentDecoder,
        private readonly HeaderValueParserInterface $headerValueParser,
    ) {
    }

    /**
     * @param resource $stream
     */
    #[\Override]
    public function parse(mixed $stream): MultipartPart
    {
        if (!\is_resource($stream)) {
            throw new \InvalidArgumentException('Input is not a stream');
        }

        ['headers' => $headers, 'bodyOffset' => $bodyOffset] = $this->headerParser->parse($stream);

        $part = new MultipartPart($headers, $stream, $bodyOffset, [], $this->contentDecoder, $this->headerValueParser);

        if (!$part->isMultiPart()) {
            return $part;
        }

        $boundary = $this->headerValueParser->getOption($part->getHeader('Content-Type'), 'boundary');

        if (null === $boundary) {
            throw new \InvalidArgumentException("Can't find boundary in content type");
        }

        $partStreams = $this->partExtractor->extract($stream, $boundary, $bodyOffset);
        $parts = \array_map(fn (mixed $s) => $this->parse($s), $partStreams);

        return new MultipartPart($headers, $stream, $bodyOffset, $parts, $this->contentDecoder, $this->headerValueParser);
    }
}
