<?php

namespace NoahVet\Reef\Test\A_Unit\Contract\Phpunit;

use NoahVet\Reef\Contract\Phpunit\MultipartBody;
use PHPUnit\Framework\TestCase;

class MultipartBodyTest extends TestCase
{
    public function testGetParametersExtractsScalarFields(): void
    {
        $rawBody = "--b\r\nContent-Disposition: form-data; name=\"title\"\r\n\r\nHello\r\n--b\r\nContent-Disposition: form-data; name=\"count\"\r\n\r\n42\r\n--b--";
        $body = new MultipartBody('b', $rawBody, 'form-data');

        self::assertSame(['title' => 'Hello', 'count' => '42'], $body->getParameters());
        self::assertSame([], $body->getFileParts());
    }

    public function testGetFilePartsExtractsFileParts(): void
    {
        $rawBody = "--b\r\nContent-Disposition: form-data; name=\"upload\"; filename=\"doc.pdf\"\r\nContent-Type: application/pdf\r\n\r\nPDFDATA\r\n--b--";
        $body = new MultipartBody('b', $rawBody, 'form-data');

        self::assertSame([], $body->getParameters());

        $parts = $body->getFileParts();
        self::assertCount(1, $parts);
        self::assertSame('upload', $parts[0]['name']);
        self::assertSame('doc.pdf', $parts[0]['filename']);
        self::assertSame('application/pdf', $parts[0]['mimeType']);
        self::assertSame('PDFDATA', $parts[0]['content']);
    }

    public function testGetParametersAndFilePartsAreSeparated(): void
    {
        $rawBody = "--b\r\nContent-Disposition: form-data; name=\"label\"\r\n\r\nmy-label\r\n--b\r\nContent-Disposition: form-data; name=\"file\"; filename=\"img.png\"\r\nContent-Type: image/png\r\n\r\nIMGDATA\r\n--b--";
        $body = new MultipartBody('b', $rawBody, 'form-data');

        self::assertSame(['label' => 'my-label'], $body->getParameters());

        $parts = $body->getFileParts();
        self::assertCount(1, $parts);
        self::assertSame('file', $parts[0]['name']);
        self::assertSame('img.png', $parts[0]['filename']);
    }

    public function testPartsWithoutNameAreSkipped(): void
    {
        // Part with no Content-Disposition → getName() returns null → skipped
        $rawBody = "--b\r\n\r\norphan-content\r\n--b--";
        $body = new MultipartBody('b', $rawBody, 'form-data');

        self::assertSame([], $body->getParameters());
        self::assertSame([], $body->getFileParts());
    }

    public function testParsingIsLazyAndCached(): void
    {
        $rawBody = "--b\r\nContent-Disposition: form-data; name=\"x\"\r\n\r\n1\r\n--b--";
        $body = new MultipartBody('b', $rawBody, 'form-data');

        // First call triggers parsing
        $params1 = $body->getParameters();
        // Second call returns cached result (same reference)
        $params2 = $body->getParameters();

        self::assertSame($params1, $params2);
    }

    public function testYamlBodyWithWhitespaceOnlyBlankLinesIsNormalized(): void
    {
        // YAML block scalars produce whitespace-only blank lines ("  \n") instead of empty lines,
        // and use \n instead of \r\n. The parser must handle both.
        $rawBody = "--b\n"
            ."Content-Disposition: form-data; name=\"return_code\"; filename=\"return_code\"\n"
            ."Content-Type: text/plain; charset=utf-8\n"
            ."  \n"   // whitespace-only blank line from YAML
            ."0\n"
            ."  \n"   // whitespace-only blank line from YAML
            ."--b--\n";

        $body = new MultipartBody('b', $rawBody, 'form-data');

        $parts = $body->getFileParts();
        self::assertCount(1, $parts);
        self::assertSame('return_code', $parts[0]['name']);
        self::assertSame('return_code', $parts[0]['filename']);
        self::assertSame('0', \trim($parts[0]['content']));
    }

    public function testFilePartFallsBackToFieldNameWhenFilenameIsMissing(): void
    {
        // Edge case: isFile() true (has filename attr), but filename is empty string
        // In practice this won't happen with the domain parser, but we test the fallback
        // A part with filename="photo.jpg" → filename should be "photo.jpg"
        $rawBody = "--b\r\nContent-Disposition: form-data; name=\"photo\"; filename=\"photo.jpg\"\r\nContent-Type: image/jpeg\r\n\r\nDATA\r\n--b--";
        $body = new MultipartBody('b', $rawBody, 'form-data');

        $parts = $body->getFileParts();
        self::assertCount(1, $parts);
        self::assertSame('photo.jpg', $parts[0]['filename']);
    }
}
