<?php

namespace Libs;

use Psr\Http\Message\ServerRequestInterface;

class MultipartFormDataParser
{
    public static function parse(ServerRequestInterface $request): array
    {
        $contentType = $request->getHeaderLine('Content-Type');
        if (!preg_match('/multipart\/form-data;\s*boundary=(?:(?:"([^"]+)")|([^;\s]+))/i', $contentType, $m)) {
            throw new \RuntimeException('Invalid multipart Content-Type');
        }

        $boundary = (isset($m[1]) && $m[1] !== '') ? $m[1] : ($m[2] ?? '');
        if ($boundary === '') {
            throw new \RuntimeException('Missing multipart boundary');
        }

        $rawBody = '';
        $stream = $request->getBody();
        if (is_object($stream) && method_exists($stream, 'getContents')) {
            $rawBody = (string)$stream->getContents();
            if (method_exists($stream, 'rewind')) {
                try {
                    $stream->rewind();
                } catch (\Throwable $e) {
                }
            }
        } else {
            $rawBody = (string)$stream;
        }

        if ($rawBody === '') {
            $rawBody = (string)file_get_contents('php://input');
        }

        $delimiter = "--" . $boundary;
        $parts = explode($delimiter, $rawBody);

        $fields = [];
        $files = [];

        foreach ($parts as $part) {
            $part = ltrim($part, "\r\n\n");
            $part = rtrim($part, "\r\n\n");

            if ($part === '' || $part === '--') {
                continue;
            }

            $split = preg_split("/\r?\n\r?\n/", $part, 2);
            if (!$split || count($split) !== 2) {
                continue;
            }

            [$rawHeaders, $body] = $split;
            $headers = self::parseHeaders($rawHeaders);

            $cd = $headers['content-disposition'] ?? '';
            if (!preg_match('/name="([^"]+)"/i', $cd, $nm)) {
                continue;
            }

            $name = $nm[1];
            $filename = null;
            if (preg_match('/filename="([^"]*)"/i', $cd, $fm)) {
                $filename = $fm[1];
            }

            $body = preg_replace("/\r\n\z/", '', $body);

            if ($filename !== null && $filename !== '') {
                $files[$name] = [
                    'field' => $name,
                    'filename' => $filename,
                    'content_type' => $headers['content-type'] ?? 'application/octet-stream',
                    'content' => $body,
                ];
            } else {
                $fields[$name] = $body;
            }
        }

        return ['fields' => $fields, 'files' => $files];
    }

    private static function parseHeaders(string $rawHeaders): array
    {
        $headers = [];
        foreach (preg_split('/\r?\n/', $rawHeaders) as $line) {
            $line = trim($line);
            if ($line === '' || strpos($line, ':') === false) {
                continue;
            }
            [$k, $v] = explode(':', $line, 2);
            $headers[strtolower(trim($k))] = trim($v);
        }
        return $headers;
    }
}
