<?php

declare(strict_types=1);

namespace NoahVet\Jane\Console\Loader;

use Jane\Component\OpenApi3\SchemaParser\SchemaParser;
use Jane\Component\OpenApiCommon\Exception\CouldNotParseException;
use Jane\Component\OpenApiCommon\Exception\OpenApiVersionSupportException;
use NoahVet\Jane\Component\OpenApi3\JaneOpenApi as OpenApi3Base;

class OpenApiMatcher extends \Jane\Component\OpenApiCommon\Console\Loader\OpenApiMatcher
{
    /**
     * @var array<class-string, SchemaParser>
     */
    protected array $schemaParsersNoahVet = [];

    public function match(string $origin): string
    {
        [$openApiClass, $openApi3Message] = $this->isOpenApi3NoahVet($origin);

        if (null === $openApiClass) {
            if (null !== $openApi3Message) {
                throw new CouldNotParseException(
                    \sprintf(
                        "Could not parse schema in OpenApi v2 nor v3 format:\n- OpenApi v3: \"%s\"\n",
                        (string) $openApi3Message,
                    ),
                );
            } else {
                throw new OpenApiVersionSupportException(
                    'Only OpenApi v2 / v3 specifications are supported, use an external tool to convert your api files.',
                );
            }
        }

        return $openApiClass;
    }

    private function isOpenApi3NoahVet(string $origin): array
    {
        $class = null;
        $message = null;

        if (\class_exists(OpenApi3Base::class)) {
            if (!\array_key_exists(OpenApi3Base::class, $this->schemaParsersNoahVet)) {
                $openApi3Serializer = OpenApi3Base::buildSerializer();
                $this->schemaParsersNoahVet[OpenApi3Base::class] = new SchemaParser($openApi3Serializer);
            }

            try {
                $this->schemaParsersNoahVet[OpenApi3Base::class]->parseSchema($origin);
                $class = OpenApi3Base::class;
            } catch (CouldNotParseException $e) {
                $message = $e->getMessage();
            } catch (OpenApiVersionSupportException) {
                // We don't need this exception, we will trigger another one if needed ~
            }
        }

        return [$class, $message];
    }
}
