<?php

namespace SwaggerBake\Test\TestCase\Lib\Attribute;

use Cake\Routing\Router;
use Cake\Routing\RouteBuilder;
use Cake\TestSuite\TestCase;
use SwaggerBake\Lib\Attribute\OpenApiSchema;
use SwaggerBake\Lib\Model\ModelScanner;
use SwaggerBake\Lib\Route\RouteScanner;
use SwaggerBake\Lib\Configuration;
use SwaggerBake\Lib\Swagger;

class OpenApiSchemaTest extends TestCase
{
    /**
     * @var string[]
     */
    public array $fixtures = [
        'plugin.SwaggerBake.Employees',
        'plugin.SwaggerBake.EmployeeSalaries',
        'plugin.SwaggerBake.DepartmentEmployees',
    ];

    private Configuration $config;

    public function setUp(): void
    {
        parent::setUp(); // TODO: Change the autogenerated stub
        Router::createRouteBuilder('/')->scope('/', function (RouteBuilder $builder) {
            $builder->setExtensions(['json']);
            $builder->resources('Employees', function (RouteBuilder $routes) {
                $routes->resources('EmployeeSalaries');
            });
            $builder->resources('DepartmentEmployees');
        });

        $this->config = new Configuration([
            'prefix' => '/',
            'yml' => '/config/swagger-bare-bones.yml',
            'json' => '/webroot/swagger.json',
            'webPath' => '/swagger.json',
            'hotReload' => false,
            'exceptionSchema' => 'Exception',
            'requestAccepts' => ['application/x-www-form-urlencoded'],
            'responseContentTypes' => ['application/json'],
            'namespaces' => [
                'controllers' => ['\SwaggerBakeTest\App\\'],
                'entities' => ['\SwaggerBakeTest\App\\'],
                'tables' => ['\SwaggerBakeTest\App\\'],
            ]
        ], SWAGGER_BAKE_TEST_APP);
    }

    public function test_entity_exists(): void
    {
        $cakeRoute = new RouteScanner(new Router(), $this->config);

        $swagger = (new Swagger(new ModelScanner($cakeRoute, $this->config), $this->config))->build();

        $arr = json_decode($swagger->toString(), true);

        $this->assertArrayHasKey('Employee', $arr['components']['schemas']);
    }

    /**
     * @see OpenApiSchema::VISIBLE_NEVER
     */
    public function test_schema_never_visible(): void
    {
        $cakeRoute = new RouteScanner(new Router(), $this->config);

        $swagger = (new Swagger(new ModelScanner($cakeRoute, $this->config), $this->config))->build();

        $arr = json_decode($swagger->toString(), true);

        $this->assertArrayNotHasKey('EmployeeSalary', $arr['components']['schemas']);
        $this->assertArrayNotHasKey('EmployeeSalary', $arr['x-swagger-bake']['components']['schemas']);
    }

    /**
     * @see OpenApiSchema::VISIBLE_HIDDEN
     */
    public function test_schema_is_hidden(): void
    {
        $cakeRoute = new RouteScanner(new Router(), $this->config);

        $swagger = (new Swagger(new ModelScanner($cakeRoute, $this->config), $this->config))->build();

        $arr = json_decode($swagger->toString(), true);

        $this->assertArrayNotHasKey('DepartmentEmployee', $arr['components']['schemas']);
        $this->assertArrayHasKey('DepartmentEmployee', $arr['x-swagger-bake']['components']['schemas']);
    }

    public function test_entity_attribute(): void
    {
        $cakeRoute = new RouteScanner(new Router(), $this->config);

        $swagger = (new Swagger(new ModelScanner($cakeRoute, $this->config), $this->config))->build();

        $arr = json_decode($swagger->toString(), true);

        $employee = $arr['components']['schemas']['Employee'];

        $this->assertEquals('string', $employee['properties']['gender']['type']);
    }

    public function test_openapi_schema_throws_invalid_arg_exception(): void
    {
        $this->expectException(\InvalidArgumentException::class);
        new OpenApiSchema(20);
    }
}