<?php

declare(strict_types=1);

/*
 * This file is part of the NelmioApiDocBundle package.
 *
 * (c) Nelmio
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Nelmio\ApiDocBundle\RouteDescriber\RouteArgumentDescriber;

use Nelmio\ApiDocBundle\OpenApiPhp\Util;
use OpenApi\Annotations as OA;
use Symfony\Component\HttpKernel\Attribute\MapUploadedFile;
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;

final class SymfonyMapUploadedFileDescriber implements RouteArgumentDescriberInterface
{
    public const CONTEXT_ARGUMENT_METADATA = 'nelmio_api_doc_bundle.argument_metadata.'.self::class;
    public const CONTEXT_MODEL_REF = 'nelmio_api_doc_bundle.model_ref.'.self::class;

    public function describe(ArgumentMetadata $argumentMetadata, OA\Operation $operation): void
    {
        if (!$attribute = $argumentMetadata->getAttributes(MapUploadedFile::class, ArgumentMetadata::IS_INSTANCEOF)[0] ?? null) {
            return;
        }

        $name = $attribute->name ?? $argumentMetadata->getName();
        $body = Util::getChild($operation, OA\RequestBody::class);

        $mediaType = Util::getCollectionItem($body, OA\MediaType::class, [
            'mediaType' => 'multipart/form-data',
        ]);

        /** @var OA\Schema $schema */
        $schema = Util::getChild($mediaType, OA\Schema::class, [
            'type' => 'object',
        ]);

        $property = Util::getCollectionItem($schema, OA\Property::class, ['property' => $name]);
        if ($argumentMetadata->isVariadic() || 'array' === $argumentMetadata->getType()) {
            Util::modifyAnnotationValue($property, 'type', 'array');
            Util::modifyAnnotationValue($property, 'items', new OA\Items([
                '_context' => Util::createWeakContext($property->_context),
                'type' => 'string',
                'format' => 'binary',
            ]));
        } else {
            Util::modifyAnnotationValue($property, 'type', 'string');
            Util::modifyAnnotationValue($property, 'format', 'binary');
        }
    }
}
