private function jsonSerializeInternal(array $seen): array {
        $fix = function ($schema) use (&$fix, $seen) {
            if ($schema instanceof Schema) {
                if (in_array($schema, $seen, true)) {
                    return ['$ref' => '#/components/schemas/'.($schema->getID() ?: '$no-id')];
                } else {
                    $seen[] = $schema;
                    return $schema->jsonSerializeInternal($seen);
                }
            }

            if (!empty($schema['type'])) {
                $types = (array)$schema['type'];

                foreach ($types as $i => &$type) {
                    // Swap datetime and timestamp to other types with formats.
                    if ($type === 'datetime') {
                        $type = 'string';
                        $schema['format'] = 'date-time';
                    } elseif ($schema['type'] === 'timestamp') {
                        $type = 'integer';
                        $schema['format'] = 'timestamp';
                    }
                }
                $types = array_unique($types);
                $schema['type'] = count($types) === 1 ? reset($types) : $types;
            }

            if (!empty($schema['items'])) {
                $schema['items'] = $fix($schema['items']);
            }
            if (!empty($schema['properties'])) {
                $properties = [];
                foreach ($schema['properties'] as $key => $property) {
                    $properties[$key] = $fix($property);
                }
                $schema['properties'] = $properties;
            }

            return $schema;
        };

        $result = $fix($this->schema);

        return $result;
    }