<?php

{{>licenseInfo}}

declare(strict_types=1);

/**
 * NOTE: This class is auto generated by the openapi generator program.
 * https://github.com/openapitools/openapi-generator
 * Do not edit the class manually.
 */{{#apiInfo}}
namespace {{appPackage}};

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Slim\Exception\HttpNotImplementedException;
{{#hasAuthMethods}}
use Dyorg\TokenAuthentication;
    {{#authMethods}}
        {{#isBasicBasic}}
use {{authPackage}}\BasicAuthenticator;
        {{/isBasicBasic}}
        {{#isApiKey}}
use {{authPackage}}\ApiKeyAuthenticator;
        {{/isApiKey}}
        {{#isOAuth}}
use {{authPackage}}\OAuthAuthenticator;
        {{/isOAuth}}
        {{#isBasicBearer}}
use {{authPackage}}\BearerAuthenticator;
        {{/isBasicBearer}}
    {{/authMethods}}
{{/hasAuthMethods}}

/**
 * RegisterRoutes Class Doc Comment
 *
 * @package {{invokerPackage}}
 * @author  OpenAPI Generator team
 * @link    https://github.com/openapitools/openapi-generator
 */
class RegisterRoutes
{
    /** @var array[] list of all api operations */
    private $operations = [
        {{#apis}}
        {{#operations}}
        {{#operation}}
        [
            'httpMethod' => '{{httpMethod}}',
            'basePathWithoutHost' => '{{{basePathWithoutHost}}}',
            'path' => '{{{path}}}',
            'apiPackage' => '{{apiPackage}}',
            'classname' => '{{classname}}',
            'userClassname' => '{{userClassname}}',
            'operationId' => '{{operationId}}',
            'responses' => [
            {{#responses}}
                '{{#isDefault}}default{{/isDefault}}{{^isDefault}}{{code}}{{/isDefault}}' => [
                    'jsonSchema' => '{{{jsonSchema}}}',
                ],
            {{/responses}}
            ],
            'authMethods' => [
                {{#hasAuthMethods}}
                {{#authMethods}}
                // {{type}} security schema named '{{name}}'
                {{#isBasicBasic}}
                [
                    'type' => '{{type}}',
                    'isBasic' => true,
                    'isBearer' => false,
                    'isApiKey' => false,
                    'isOAuth' => false,
                ],
                {{/isBasicBasic}}
                {{#isBasicBearer}}
                [
                    'type' => '{{type}}',
                    'scheme' => '{{scheme}}',
                    'bearerFormat' => '{{bearerFormat}}',
                    'isBasic' => false,
                    'isBearer' => true,
                    'isApiKey' => false,
                    'isOAuth' => false,
                ],
                {{/isBasicBearer}}
                {{#isApiKey}}
                [
                    'type' => '{{type}}',
                    'isBasic' => false,
                    'isBearer' => false,
                    'isApiKey' => true,
                    'isOAuth' => false,
                    'keyParamName' => '{{keyParamName}}',
                    'isKeyInHeader' => {{#isKeyInHeader}}true{{/isKeyInHeader}}{{^isKeyInHeader}}false{{/isKeyInHeader}},
                    'isKeyInQuery' => {{#isKeyInQuery}}true{{/isKeyInQuery}}{{^isKeyInQuery}}false{{/isKeyInQuery}},
                    'isKeyInCookie' => {{#isKeyInCookie}}true{{/isKeyInCookie}}{{^isKeyInCookie}}false{{/isKeyInCookie}},
                ],
                {{/isApiKey}}
                {{#isOAuth}}
                [
                    'type' => '{{type}}',
                    'isBasic' => false,
                    'isBearer' => false,
                    'isApiKey' => false,
                    'isOAuth' => true,
                    'scopes' => [
                    {{#scopes}}
                        '{{scope}}',{{#description}} // {{.}}{{/description}}
                    {{/scopes}}
                    ],
                ],
                {{/isOAuth}}
                {{/authMethods}}
                {{/hasAuthMethods}}
            ],
        ],
        {{/operation}}
        {{/operations}}
        {{/apis}}
    ];

    /**
     * Add routes to Slim app.
     *
     * @param \Slim\App $app Pre-configured Slim application instance
     *
     * @throws HttpNotImplementedException When implementation class doesn't exists
     */
    public function __invoke(\Slim\App $app): void
    {
        $app->options('/{routes:.*}', function (ServerRequestInterface $request, ResponseInterface $response) {
            // CORS Pre-Flight OPTIONS Request Handler
            return $response;
        });

        // create mock middleware factory
        /** @var \Psr\Container\ContainerInterface */
        $container = $app->getContainer();
        /** @var \OpenAPIServer\Mock\OpenApiDataMockerRouteMiddlewareFactory|null */
        $mockMiddlewareFactory = null;
        if ($container->has(\OpenAPIServer\Mock\OpenApiDataMockerRouteMiddlewareFactory::class)) {
            // I know, anti-pattern. Don't retrieve dependency directly from container
            $mockMiddlewareFactory = $container->get(\OpenAPIServer\Mock\OpenApiDataMockerRouteMiddlewareFactory::class);
        }

        foreach ($this->operations as $operation) {
            $callback = function (ServerRequestInterface $request) use ($operation) {
                $message = "How about extending {$operation['classname']} by {$operation['apiPackage']}\\{$operation['userClassname']} class implementing {$operation['operationId']} as a {$operation['httpMethod']} method?";
                throw new HttpNotImplementedException($request, $message);
            };
            $middlewares = [];

            if (class_exists("\\{$operation['apiPackage']}\\{$operation['userClassname']}")) {
                // Notice how we register the controller using the class name?
                // PHP-DI will instantiate the class for us only when it's actually necessary
                $callback = ["\\{$operation['apiPackage']}\\{$operation['userClassname']}", $operation['operationId']];
            }

            if ($mockMiddlewareFactory) {
                $mockSchemaResponses = array_map(function ($item) {
                    return json_decode($item['jsonSchema'], true);
                }, $operation['responses']);
                $middlewares[] = $mockMiddlewareFactory->create($mockSchemaResponses);
            }

            $route = $app->map(
                [$operation['httpMethod']],
                "{$operation['basePathWithoutHost']}{$operation['path']}",
                $callback
            )->setName($operation['operationId']);

            {{#hasAuthMethods}}
            // Add authentication middleware based on the operation's authMethods
            if ($operation['authMethods']) {
                foreach ($operation['authMethods'] as $authMethod) {
                    {{#authMethods}}
                        {{#isBasicBasic}}
                    if ($authMethod['isBasic']) {
                        $route->add(new TokenAuthentication([
                            'path' => '/',
                            'authenticator' => new BasicAuthenticator,
                            'regex' => '/Basic\s+(.*)$/i',
                            'header' => 'Authorization',
                            'parameter' => null,
                            'cookie' => null,
                            'argument' => null,
                            'attribute' => 'authorization_token',
                            'error' => ['{{authPackage}}\BasicAuthenticator', 'handleUnauthorized'],
                        ]));
                    }
                        {{/isBasicBasic}}
                        {{#isApiKey}}
                    if ($authMethod['isApiKey']) {
                        $authenticatorConfig = [
                            'path' => '/',
                            'authenticator' => new ApiKeyAuthenticator,
                            'regex' => '/\s+(.*)$/i',
                            'argument' => null,
                            'attribute' => 'authorization_token',
                            'error' => ['{{authPackage}}\ApiKeyAuthenticator', 'handleUnauthorized'],
                        ];
                        if ($authMethod['isKeyInHeader']) {
                            $authenticatorConfig = [
                                'header' => $authMethod['keyParamName'],
                                'parameter' => null,
                                'cookie' => null,
                            ]
                        } else if ($authMethod['isKeyInQuery']) {
                            $authenticatorConfig = [
                                'header' => null,
                                'parameter' => $authMethod['keyParamName'],
                                'cookie' => null,
                            ]
                        } else if ($authMethod['isKeyInCookie']) {
                            $authenticatorConfig = [
                                'header' => null,
                                'parameter' => null,
                                'cookie' => $authMethod['keyParamName'],
                            ]
                        }
                        $route->add(new TokenAuthentication($authenticatorConfig));
                    }
                        {{/isApiKey}}
                        {{#isBasicBearer}}
                    if ($authMethod['isBearer']) {
                        $route->add(new TokenAuthentication([
                            'path' => '/',
                            'authenticator' => new BearerAuthenticator,
                            'regex' => '/Bearer\s+(.*)$/i',
                            'header' => 'Authorization',
                            'parameter' => null,
                            'cookie' => null,
                            'argument' => null,
                            'attribute' => 'authorization_token',
                            'error' => ['{{authPackage}}\BearerAuthenticator', 'handleUnauthorized'],
                        ]));
                    }
                        {{/isBasicBearer}}
                        {{#isOAuth}}
                    if ($authMethod['isOAuth']) {
                        $route->add(new TokenAuthentication([
                            'path' => '/',
                            'authenticator' => new OAuthAuthenticator($authMethod['scopes']),
                            'regex' => '/Bearer\s+(.*)$/i',
                            'header' => 'Authorization',
                            'parameter' => null,
                            'cookie' => null,
                            'argument' => null,
                            'attribute' => 'authorization_token',
                            'error' => ['{{authPackage}}\OAuthAuthenticator', 'handleUnauthorized'],
                        ]));
                    }
                        {{/isOAuth}}
                    {{/authMethods}}
                }
            }
            {{/hasAuthMethods}}

            foreach ($middlewares as $middleware) {
                $route->add($middleware);
            }
        }
    }
}
{{/apiInfo}}
