# spec/requests/api/v1/lap_times_spec.rb
require 'swagger_helper'

RSpec.describe 'Lap Times API', type: :request do
  path '/api/v1/lap_times' do
    get 'List all lap times' do
      tags 'Lap Times'
      produces 'application/json'

      parameter name: :driver_id, in: :query, type: :integer, required: false, description: 'Filter by driver ID'
      parameter name: :circuit_id, in: :query, type: :integer, required: false, description: 'Filter by circuit ID'
      parameter name: :lap_min, in: :query, type: :integer, required: false, description: 'Minimum lap number'
      parameter name: :lap_max, in: :query, type: :integer, required: false, description: 'Maximum lap number'

      response '200', 'lap times found' do
        schema type: :array,
          items: {
            type: :object,
            properties: {
              id: { type: :integer },
              driver_id: { type: :integer },
              circuit_id: { type: :integer },
              time_ms: { type: :integer },
              lap_number: { type: :integer },
              created_at: { type: :string, format: 'date-time' },
              updated_at: { type: :string, format: 'date-time' }
            },
            required: ['id', 'driver_id', 'circuit_id', 'time_ms', 'lap_number']
          }

        run_test!
      end
    end

    post 'Create a lap time' do
      tags 'Lap Times'
      consumes 'application/json'
      produces 'application/json'

      parameter name: :lap_time, in: :body, schema: {
        type: :object,
        properties: {
          driver_id: { type: :integer },
          circuit_id: { type: :integer },
          time_ms: { type: :integer },
          lap_number: { type: :integer }
        },
        required: ['driver_id', 'circuit_id', 'time_ms', 'lap_number']
      }

      response '201', 'lap time created' do
        let(:lap_time) { { driver_id: 1, circuit_id: 1, time_ms: 80000, lap_number: 1 } }
        run_test!
      end

      response '422', 'invalid request' do
        let(:lap_time) { { driver_id: 1 } }
        run_test!
      end
    end
  end

  # Document nested routes
  path '/api/v1/drivers/{driver_id}/lap_times' do
    get 'Get lap times for a specific driver' do
      tags 'Lap Times'
      produces 'application/json'

      parameter name: :driver_id, in: :path, type: :integer, required: true

      response '200', 'lap times found' do
        let(:driver_id) { 1 }
        schema type: :array,
          items: {
            type: :object,
            properties: {
              id: { type: :integer },
              circuit_id: { type: :integer },
              time_ms: { type: :integer },
              lap_number: { type: :integer },
              created_at: { type: :string, format: 'date-time' },
              updated_at: { type: :string, format: 'date-time' }
            }
          }
        run_test!
      end
    end
  end
end
```

This more detailed spec documents multiple HTTP methods, query parameters, request bodies, different response types, and nested routes. The `let` statements provide test data that will be used when executing the tests.

### Understanding the Rswag DSL

When writing Rswag documentation specs, the following elements are used to describe the API:

- **Path and HTTP method definitions:** The `path` method defines the API endpoint being documented.

  ```ruby drivers_spec.rb
  path '/api/v1/drivers' do
    get 'List all drivers' do
      # Documentation for GET request
    end
  end
  ```

- **Tags for organization:** Tags help group related operations together, making your documentation more organized.

  ```ruby
  path '/api/v1/drivers' do
    get 'List all drivers' do
      tags 'Drivers'
      # Other documentation
    end
  end
  ```

- **Content types:** Specify what your API consumes and produces.

  ```ruby drivers_spec.rb
  path '/api/v1/drivers' do
    get 'List all drivers' do
      tags 'Drivers'
      produces 'application/json'
      consumes 'application/json'
      # Other documentation
    end
  end
  ```

- **Document parameters:** Define the query, path, or body parameters.

  ```ruby drivers_spec.rb
  path '/api/v1/drivers' do
    get 'List all drivers' do
      tags 'Drivers'
      produces 'application/json'

      parameter name: :team, in: :query, type: :string, required: false, description: 'Filter drivers by team'

      # Other documentation
    end
  end
  ```

- **Response definitions:** Define the possible responses with their schemas.

  ```ruby drivers_spec.rb
  path '/api/v1/drivers' do
    get 'List all drivers' do
      tags 'Drivers'
      produces 'application/json'

      parameter name: :team, in: :query, type: :string, required: false, description: 'Filter drivers by team'

      response '200', 'drivers found' do
        schema type: :array,
          items: {
            type: :object,
            properties: {
              id: { type: :integer },
              name: { type: :string },
              code: { type: :string }
            }
          }
        run_test!
      end
    end
  end
  ```

- **Test data:** Provide test data by using the `let` syntax to define the values that will be used during testing.

  ```ruby filename="drivers_spec.rb"
  path '/api/v1/drivers' do
    post 'Create a driver' do
      # ... parameter and other definitions ...

      response '201', 'driver created' do
        let(:driver) { { name: 'Max Verstappen', code: 'VER' } }
        run_test!
      end
    end
  end
  ```

## Generating the OpenAPI document

After writing documentation specs, generate the OpenAPI document by running a single `rake` task:

```bash
rake rswag:specs:swaggerize
```

Alternatively, run the aliased command:

```bash
rake rswag
```

If the command fails, set the environment to "test" using:

```bash
RAILS_ENV=test rails rswag
```

This command performs two important steps:

- Runs Rswag specs to validate that the API implementation matches the documentation.
- It generates the OpenAPI document file at the configured location.

The result is an OpenAPI document (for example, `openapi/v1/openapi.yaml`) usable with various tools, including the built-in OpenAPI UI and the Speakeasy CLI.

If tests fail during this process, it indicates that the API implementation doesn't match the documentation. This behavior ensures documentation stays accurate and aligned with the actual implementation.

### Understanding the generated OpenAPI document

After running the `rswag:specs:swaggerize` command, Rswag generates a comprehensive OpenAPI document. Here's what a section of that generated document looks like for the lap times endpoint:

```yaml filename="openapi.yaml"