<?php

namespace NoahVet\Reef\Infrastructure\Phpunit\Loader;

use NoahVet\Reef\Contract\Phpunit\ExampleLoaderInterface;
use NoahVet\Reef\Contract\Phpunit\JsonBody;
use NoahVet\Reef\Contract\Phpunit\MultipartBody;
use NoahVet\Reef\Contract\Phpunit\RawBodyInterface;
use Symfony\Component\Yaml\Yaml;

class OasExampleLoader implements ExampleLoaderInterface
{
    /** @return array<mixed>|RawBodyInterface */
    #[\Override]
    public function load(string $filePath, string $componentName): array|RawBodyInterface
    {
        $extension = \strtolower(\pathinfo($filePath, \PATHINFO_EXTENSION));

        $content = \file_get_contents($filePath);
        if (false === $content) {
            throw new \RuntimeException(\sprintf('Could not read file "%s".', $filePath));
        }

        $data = match ($extension) {
            'yaml', 'yml' => Yaml::parse($content),
            'json' => \json_decode($content, true, 512, \JSON_THROW_ON_ERROR),
            default => throw new \InvalidArgumentException(
                \sprintf('Unsupported file format ".%s". Supported formats: yaml, yml, json.', $extension),
            ),
        };

        if (!isset($data['components']['examples'][$componentName])) {
            throw new \RuntimeException(
                \sprintf('Component "%s" not found in "%s".', $componentName, $filePath),
            );
        }

        $value = $data['components']['examples'][$componentName] ?? [];

        // Cas OpenAPI 3 valide
        if (
            \is_array($value['value'] ?? null)
            && \is_string($value['summary'] ?? null)
        ) {
            return $value['value'];
        }

        // multipart request
        if (
            \is_string($value['value'] ?? null)
            && \is_string($value['summary'] ?? null)
            && \str_starts_with($value['value'], '--')
        ) {
            return $this->parseMultipartBody($value['value'], $this->extractMultipartSubtype($value['x-content-type'] ?? null));
        }

        // other raw query
        if (
            \is_string($value['value'] ?? null)
            && \is_string($value['summary'] ?? null)
        ) {
            return new JsonBody($value['value']);
        }

        // Par défaut, retourne tout l'objet
        return $value;
    }

    private function parseMultipartBody(string $raw, string $subtype = 'related'): MultipartBody
    {
        $firstLine = \trim(\explode("\n", \ltrim($raw))[0]);
        if (!\str_starts_with($firstLine, '--')) {
            throw new \RuntimeException(
                'Cannot parse multipart body: first line must start with "--<boundary>".',
            );
        }

        return new MultipartBody(\substr($firstLine, 2), $raw, $subtype);
    }

    private function extractMultipartSubtype(?string $contentType): string
    {
        if (null === $contentType) {
            return 'related';
        }

        if (\str_starts_with($contentType, 'multipart/')) {
            return \substr($contentType, \strlen('multipart/'));
        }

        return $contentType;
    }
}
