# This file was auto-generated by Fern from our API Definition.

import contextlib
import datetime as dt
import json
import typing
from json.decoder import JSONDecodeError

import httpx_sse
from ..core.api_error import ApiError
from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
from ..core.http_response import AsyncHttpResponse, HttpResponse
from ..core.jsonable_encoder import jsonable_encoder
from ..core.pydantic_utilities import parse_obj_as
from ..core.request_options import RequestOptions
from ..core.serialization import convert_and_respect_annotation_metadata
from ..errors.bad_request_error import BadRequestError
from ..errors.not_found_error import NotFoundError
from ..errors.request_timeout_error import RequestTimeoutError
from ..errors.too_many_requests_error import TooManyRequestsError
from ..errors.unauthorized_error import UnauthorizedError
from ..types.aliases import Aliases
from ..types.classification import Classification
from ..types.correlation import Correlation
from ..types.dimensions import Dimensions
from ..types.entity import Entity
from ..types.entity_event_response import EntityEventResponse
from ..types.geo_details import GeoDetails
from ..types.geo_shape import GeoShape
from ..types.group_details import GroupDetails
from ..types.health import Health
from ..types.indicators import Indicators
from ..types.location import Location
from ..types.location_uncertainty import LocationUncertainty
from ..types.media import Media
from ..types.mil_view import MilView
from ..types.ontology import Ontology
from ..types.orbit import Orbit
from ..types.overrides import Overrides
from ..types.payloads import Payloads
from ..types.power_state import PowerState
from ..types.provenance import Provenance
from ..types.relationships import Relationships
from ..types.route_details import RouteDetails
from ..types.schedules import Schedules
from ..types.sensors import Sensors
from ..types.signal import Signal
from ..types.status import Status
from ..types.supplies import Supplies
from ..types.symbology import Symbology
from ..types.target_priority import TargetPriority
from ..types.task_catalog import TaskCatalog
from ..types.tracked import Tracked
from ..types.transponder_codes import TransponderCodes
from ..types.visual_details import VisualDetails
from .types.stream_entities_response import StreamEntitiesResponse

# this is used as the default value for optional parameters
OMIT = typing.cast(typing.Any, ...)


class RawEntitiesClient:
    def __init__(self, *, client_wrapper: SyncClientWrapper):
        self._client_wrapper = client_wrapper

    def publish_entity(
        self,
        *,
        entity_id: typing.Optional[str] = OMIT,
        description: typing.Optional[str] = OMIT,
        is_live: typing.Optional[bool] = OMIT,
        created_time: typing.Optional[dt.datetime] = OMIT,
        expiry_time: typing.Optional[dt.datetime] = OMIT,
        no_expiry: typing.Optional[bool] = OMIT,
        status: typing.Optional[Status] = OMIT,
        location: typing.Optional[Location] = OMIT,
        location_uncertainty: typing.Optional[LocationUncertainty] = OMIT,
        geo_shape: typing.Optional[GeoShape] = OMIT,
        geo_details: typing.Optional[GeoDetails] = OMIT,
        aliases: typing.Optional[Aliases] = OMIT,
        tracked: typing.Optional[Tracked] = OMIT,
        correlation: typing.Optional[Correlation] = OMIT,
        mil_view: typing.Optional[MilView] = OMIT,
        ontology: typing.Optional[Ontology] = OMIT,
        sensors: typing.Optional[Sensors] = OMIT,
        payloads: typing.Optional[Payloads] = OMIT,
        power_state: typing.Optional[PowerState] = OMIT,
        provenance: typing.Optional[Provenance] = OMIT,
        overrides: typing.Optional[Overrides] = OMIT,
        indicators: typing.Optional[Indicators] = OMIT,
        target_priority: typing.Optional[TargetPriority] = OMIT,
        signal: typing.Optional[Signal] = OMIT,
        transponder_codes: typing.Optional[TransponderCodes] = OMIT,
        data_classification: typing.Optional[Classification] = OMIT,
        task_catalog: typing.Optional[TaskCatalog] = OMIT,
        media: typing.Optional[Media] = OMIT,
        relationships: typing.Optional[Relationships] = OMIT,
        visual_details: typing.Optional[VisualDetails] = OMIT,
        dimensions: typing.Optional[Dimensions] = OMIT,
        route_details: typing.Optional[RouteDetails] = OMIT,
        schedules: typing.Optional[Schedules] = OMIT,
        health: typing.Optional[Health] = OMIT,
        group_details: typing.Optional[GroupDetails] = OMIT,
        supplies: typing.Optional[Supplies] = OMIT,
        orbit: typing.Optional[Orbit] = OMIT,
        symbology: typing.Optional[Symbology] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> HttpResponse[Entity]:
        """
        Publish an entity for ingest into the Entities API. Entities created with this method are "owned" by the originator: other sources,
        such as the UI, may not edit or delete these entities. The server validates entities at API call time and
        returns an error if the entity is invalid.

        An entity ID must be provided when calling this endpoint. If the entity referenced by the entity ID does not exist
        then it will be created. Otherwise the entity will be updated. An entity will only be updated if its
        provenance.sourceUpdateTime is greater than the provenance.sourceUpdateTime of the existing entity.

        Parameters
        ----------
        entity_id : typing.Optional[str]
            A Globally Unique Identifier (GUID) for your entity. If this field is empty, the Entity Manager API
             automatically generates an ID when it creates the entity.

        description : typing.Optional[str]
            A human-readable entity description that's helpful for debugging purposes and human
             traceability. If this field is empty, the Entity Manager API generates one for you.

        is_live : typing.Optional[bool]
            Indicates the entity is active and should have a lifecycle state of CREATE or UPDATE.
             Set this field to true when publishing an entity.

        created_time : typing.Optional[dt.datetime]
            The time when the entity was first known to the entity producer. If this field is empty, the Entity Manager API uses the
             current timestamp of when the entity is first received.
             For example, when a drone is first powered on, it might report its startup time as the created time.
             The timestamp doesn't change for the lifetime of an entity.

        expiry_time : typing.Optional[dt.datetime]
            Future time that expires an entity and updates the is_live flag.
             For entities that are constantly updating, the expiry time also updates.
             In some cases, this may differ from is_live.
             Example: Entities with tasks exported to an external system must remain
             active even after they expire.
             This field is required when publishing a prepopulated entity.
             The expiry time must be in the future, but less than 30 days from the current time.

        no_expiry : typing.Optional[bool]
            Use noExpiry only when the entity contains information that should be available to other
             tasks or integrations beyond its immediate operational context. For example, use noExpiry
             for long-living geographical entities that maintain persistent relevance across multiple
             operations or tasks.

        status : typing.Optional[Status]
            Human-readable descriptions of what the entity is currently doing.

        location : typing.Optional[Location]
            Geospatial data related to the entity, including its position, kinematics, and orientation.

        location_uncertainty : typing.Optional[LocationUncertainty]
            Indicates uncertainty of the entity's position and kinematics.

        geo_shape : typing.Optional[GeoShape]
            Geospatial representation of the entity, including entities that cover an area rather than a fixed point.

        geo_details : typing.Optional[GeoDetails]
            Additional details on what the geospatial area or point represents, along with visual display details.

        aliases : typing.Optional[Aliases]
            Entity name displayed in the Lattice UI side panel. Also includes identifiers that other systems can use to reference the same entity.

        tracked : typing.Optional[Tracked]
            If this entity is tracked by another entity, this component contains data related to how it's being tracked.

        correlation : typing.Optional[Correlation]
            If this entity has been correlated or decorrelated to another one, this component contains information on the correlation or decorrelation.

        mil_view : typing.Optional[MilView]
            View of the entity.

        ontology : typing.Optional[Ontology]
            Ontology defines an entity's categorization in Lattice, and improves data retrieval and integration. Builds a standardized representation of the entity.

        sensors : typing.Optional[Sensors]
            Details an entity's available sensors.

        payloads : typing.Optional[Payloads]
            Details an entity's available payloads.

        power_state : typing.Optional[PowerState]
            Details the entity's power source.

        provenance : typing.Optional[Provenance]
            The primary data source provenance for this entity.

        overrides : typing.Optional[Overrides]
            Provenance of override data.

        indicators : typing.Optional[Indicators]
            Describes an entity's specific characteristics and the operations that can be performed on the entity.
             For example, "simulated" informs the operator that the entity is from a simulation, and "deletable"
             informs the operator (and system) that the delete operation is valid against the entity.

        target_priority : typing.Optional[TargetPriority]
            The prioritization associated with an entity, such as if it's a threat or a high-value target.

        signal : typing.Optional[Signal]
            Describes an entity's signal characteristics, primarily used when an entity is a signal of interest.

        transponder_codes : typing.Optional[TransponderCodes]
            A message describing any transponder codes associated with Mode 1, 2, 3, 4, 5, S interrogations. These are related to ADS-B modes.

        data_classification : typing.Optional[Classification]
            Describes an entity's security classification levels at an overall classification level and on a per
             field level.

        task_catalog : typing.Optional[TaskCatalog]
            A catalog of tasks that can be performed by an entity.

        media : typing.Optional[Media]
            Media associated with an entity, such as videos, images, or thumbnails.

        relationships : typing.Optional[Relationships]
            The relationships between this entity and other entities in the common operational picture (COP).

        visual_details : typing.Optional[VisualDetails]
            Visual details associated with the display of an entity in the client.

        dimensions : typing.Optional[Dimensions]
            Physical dimensions of the entity.

        route_details : typing.Optional[RouteDetails]
            Additional information about an entity's route.

        schedules : typing.Optional[Schedules]
            Schedules associated with this entity.

        health : typing.Optional[Health]
            Health metrics or connection status reported by the entity.

        group_details : typing.Optional[GroupDetails]
            Details for the group associated with this entity.

        supplies : typing.Optional[Supplies]
            Contains relevant supply information for the entity, such as fuel.

        orbit : typing.Optional[Orbit]
            Orbit information for space objects.

        symbology : typing.Optional[Symbology]
            Symbology/iconography for the entity respecting an existing standard.

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        HttpResponse[Entity]
            The request was valid and accepted.
        """
        _response = self._client_wrapper.httpx_client.request(
            "api/v1/entities",
            method="PUT",
            json={
                "entityId": entity_id,
                "description": description,
                "isLive": is_live,
                "createdTime": created_time,
                "expiryTime": expiry_time,
                "noExpiry": no_expiry,
                "status": convert_and_respect_annotation_metadata(object_=status, annotation=Status, direction="write"),
                "location": convert_and_respect_annotation_metadata(
                    object_=location, annotation=Location, direction="write"
                ),
                "locationUncertainty": convert_and_respect_annotation_metadata(
                    object_=location_uncertainty, annotation=LocationUncertainty, direction="write"
                ),
                "geoShape": convert_and_respect_annotation_metadata(
                    object_=geo_shape, annotation=GeoShape, direction="write"
                ),
                "geoDetails": convert_and_respect_annotation_metadata(
                    object_=geo_details, annotation=GeoDetails, direction="write"
                ),
                "aliases": convert_and_respect_annotation_metadata(
                    object_=aliases, annotation=Aliases, direction="write"
                ),
                "tracked": convert_and_respect_annotation_metadata(
                    object_=tracked, annotation=Tracked, direction="write"
                ),
                "correlation": convert_and_respect_annotation_metadata(
                    object_=correlation, annotation=Correlation, direction="write"
                ),
                "milView": convert_and_respect_annotation_metadata(
                    object_=mil_view, annotation=MilView, direction="write"
                ),
                "ontology": convert_and_respect_annotation_metadata(
                    object_=ontology, annotation=Ontology, direction="write"
                ),
                "sensors": convert_and_respect_annotation_metadata(
                    object_=sensors, annotation=Sensors, direction="write"
                ),
                "payloads": convert_and_respect_annotation_metadata(
                    object_=payloads, annotation=Payloads, direction="write"
                ),
                "powerState": convert_and_respect_annotation_metadata(
                    object_=power_state, annotation=PowerState, direction="write"
                ),
                "provenance": convert_and_respect_annotation_metadata(
                    object_=provenance, annotation=Provenance, direction="write"
                ),
                "overrides": convert_and_respect_annotation_metadata(
                    object_=overrides, annotation=Overrides, direction="write"
                ),
                "indicators": convert_and_respect_annotation_metadata(
                    object_=indicators, annotation=Indicators, direction="write"
                ),
                "targetPriority": convert_and_respect_annotation_metadata(
                    object_=target_priority, annotation=TargetPriority, direction="write"
                ),
                "signal": convert_and_respect_annotation_metadata(object_=signal, annotation=Signal, direction="write"),
                "transponderCodes": convert_and_respect_annotation_metadata(
                    object_=transponder_codes, annotation=TransponderCodes, direction="write"
                ),
                "dataClassification": convert_and_respect_annotation_metadata(
                    object_=data_classification, annotation=Classification, direction="write"
                ),
                "taskCatalog": convert_and_respect_annotation_metadata(
                    object_=task_catalog, annotation=TaskCatalog, direction="write"
                ),
                "media": convert_and_respect_annotation_metadata(object_=media, annotation=Media, direction="write"),
                "relationships": convert_and_respect_annotation_metadata(
                    object_=relationships, annotation=Relationships, direction="write"
                ),
                "visualDetails": convert_and_respect_annotation_metadata(
                    object_=visual_details, annotation=VisualDetails, direction="write"
                ),
                "dimensions": convert_and_respect_annotation_metadata(
                    object_=dimensions, annotation=Dimensions, direction="write"
                ),
                "routeDetails": convert_and_respect_annotation_metadata(
                    object_=route_details, annotation=RouteDetails, direction="write"
                ),
                "schedules": convert_and_respect_annotation_metadata(
                    object_=schedules, annotation=Schedules, direction="write"
                ),
                "health": convert_and_respect_annotation_metadata(object_=health, annotation=Health, direction="write"),
                "groupDetails": convert_and_respect_annotation_metadata(
                    object_=group_details, annotation=GroupDetails, direction="write"
                ),
                "supplies": convert_and_respect_annotation_metadata(
                    object_=supplies, annotation=Supplies, direction="write"
                ),
                "orbit": convert_and_respect_annotation_metadata(object_=orbit, annotation=Orbit, direction="write"),
                "symbology": convert_and_respect_annotation_metadata(
                    object_=symbology, annotation=Symbology, direction="write"
                ),
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    Entity,
                    parse_obj_as(
                        type_=Entity,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            if _response.status_code == 400:
                raise BadRequestError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 401:
                raise UnauthorizedError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    def get_entity(
        self, entity_id: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> HttpResponse[Entity]:
        """
        Parameters
        ----------
        entity_id : str
            ID of the entity to return

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        HttpResponse[Entity]
            Entity retrieval was successful
        """
        _response = self._client_wrapper.httpx_client.request(
            f"api/v1/entities/{jsonable_encoder(entity_id)}",
            method="GET",
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    Entity,
                    parse_obj_as(
                        type_=Entity,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            if _response.status_code == 400:
                raise BadRequestError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 401:
                raise UnauthorizedError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 404:
                raise NotFoundError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    def override_entity(
        self,
        entity_id: str,
        field_path: str,
        *,
        entity: typing.Optional[Entity] = OMIT,
        provenance: typing.Optional[Provenance] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> HttpResponse[Entity]:
        """
        Only fields marked with overridable can be overridden. Please refer to our documentation to see the comprehensive
        list of fields that can be overridden. The entity in the request body should only have a value set on the field
        specified in the field path parameter. Field paths are rooted in the base entity object and must be represented
        using lower_snake_case. Do not include "entity" in the field path.

        Note that overrides are applied in an eventually consistent manner. If multiple overrides are created
        concurrently for the same field path, the last writer wins.

        Parameters
        ----------
        entity_id : str
            The unique ID of the entity to override

        field_path : str
            fieldPath to override

        entity : typing.Optional[Entity]
            The entity containing the overridden fields. The service will extract the overridable fields from
            the object and ignore all other fields.

        provenance : typing.Optional[Provenance]
            Additional information about the source of the override.

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        HttpResponse[Entity]
            The Entities API accepts the override.
        """
        _response = self._client_wrapper.httpx_client.request(
            f"api/v1/entities/{jsonable_encoder(entity_id)}/override/{jsonable_encoder(field_path)}",
            method="PUT",
            json={
                "entity": convert_and_respect_annotation_metadata(object_=entity, annotation=Entity, direction="write"),
                "provenance": convert_and_respect_annotation_metadata(
                    object_=provenance, annotation=Provenance, direction="write"
                ),
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    Entity,
                    parse_obj_as(
                        type_=Entity,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            if _response.status_code == 400:
                raise BadRequestError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 401:
                raise UnauthorizedError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 404:
                raise NotFoundError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    def remove_entity_override(
        self, entity_id: str, field_path: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> HttpResponse[Entity]:
        """
        This operation clears the override value from the specified field path on the entity.

        Parameters
        ----------
        entity_id : str
            The unique ID of the entity to undo an override from.

        field_path : str
            The fieldPath to clear overrides from.

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        HttpResponse[Entity]
            The removal of entity override was successful.
        """
        _response = self._client_wrapper.httpx_client.request(
            f"api/v1/entities/{jsonable_encoder(entity_id)}/override/{jsonable_encoder(field_path)}",
            method="DELETE",
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    Entity,
                    parse_obj_as(
                        type_=Entity,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            if _response.status_code == 400:
                raise BadRequestError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 401:
                raise UnauthorizedError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 404:
                raise NotFoundError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    def long_poll_entity_events(
        self,
        *,
        session_token: str,
        batch_size: typing.Optional[int] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> HttpResponse[EntityEventResponse]:
        """
        This is a long polling API that will first return all pre-existing data and then return all new data as
        it becomes available. If you want to start a new polling session then open a request with an empty
        'sessionToken' in the request body. The server will return a new session token in the response.
        If you want to retrieve the next batch of results from an existing polling session then send the session
        token you received from the server in the request body. If no new data is available then the server will
        hold the connection open for up to 5 minutes. After the 5 minute timeout period, the server will close the
        connection with no results and you may resume polling with the same session token. If your session falls behind
        more than 3x the total number of entities in the environment, the server will terminate your session.
        In this case you must start a new session by sending a request with an empty session token.

        Parameters
        ----------
        session_token : str
            Long-poll session identifier. Leave empty to start a new polling session.

        batch_size : typing.Optional[int]
            Maximum size of response batch. Defaults to 100. Must be between 1 and 2000 (inclusive).

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        HttpResponse[EntityEventResponse]
            Entity event batch retrieval was successful
        """
        _response = self._client_wrapper.httpx_client.request(
            "api/v1/entities/events",
            method="POST",
            json={
                "sessionToken": session_token,
                "batchSize": batch_size,
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    EntityEventResponse,
                    parse_obj_as(
                        type_=EntityEventResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            if _response.status_code == 400:
                raise BadRequestError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 401:
                raise UnauthorizedError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 404:
                raise NotFoundError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 408:
                raise RequestTimeoutError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 429:
                raise TooManyRequestsError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    @contextlib.contextmanager
    def stream_entities(
        self,
        *,
        heartbeat_interval_ms: typing.Optional[int] = OMIT,
        pre_existing_only: typing.Optional[bool] = OMIT,
        components_to_include: typing.Optional[typing.Sequence[str]] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> typing.Iterator[HttpResponse[typing.Iterator[StreamEntitiesResponse]]]:
        """
        Establishes a persistent connection to stream entity events as they occur.

        Parameters
        ----------
        heartbeat_interval_ms : typing.Optional[int]
            at what interval to send heartbeat events, defaults to 30s.

        pre_existing_only : typing.Optional[bool]
            only stream pre-existing entities in the environment and then close the connection, defaults to false.

        components_to_include : typing.Optional[typing.Sequence[str]]
            list of components to include, leave empty to include all components.

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Yields
        ------
        typing.Iterator[HttpResponse[typing.Iterator[StreamEntitiesResponse]]]
            Returns all pre-existing data and then return all new data as they become available.
        """
        with self._client_wrapper.httpx_client.stream(
            "api/v1/entities/stream",
            method="POST",
            json={
                "heartbeatIntervalMS": heartbeat_interval_ms,
                "preExistingOnly": pre_existing_only,
                "componentsToInclude": components_to_include,
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        ) as _response:

            def _stream() -> HttpResponse[typing.Iterator[StreamEntitiesResponse]]:
                try:
                    if 200 <= _response.status_code < 300:

                        def _iter():
                            _event_source = httpx_sse.EventSource(_response)
                            for _sse in _event_source.iter_sse():
                                if _sse.data == None:
                                    return
                                try:
                                    yield typing.cast(
                                        StreamEntitiesResponse,
                                        parse_obj_as(
                                            type_=StreamEntitiesResponse,  # type: ignore
                                            object_=json.loads(_sse.data),
                                        ),
                                    )
                                except Exception:
                                    pass
                            return

                        return HttpResponse(response=_response, data=_iter())
                    _response.read()
                    if _response.status_code == 400:
                        raise BadRequestError(
                            headers=dict(_response.headers),
                            body=typing.cast(
                                typing.Optional[typing.Any],
                                parse_obj_as(
                                    type_=typing.Optional[typing.Any],  # type: ignore
                                    object_=_response.json(),
                                ),
                            ),
                        )
                    if _response.status_code == 401:
                        raise UnauthorizedError(
                            headers=dict(_response.headers),
                            body=typing.cast(
                                typing.Optional[typing.Any],
                                parse_obj_as(
                                    type_=typing.Optional[typing.Any],  # type: ignore
                                    object_=_response.json(),
                                ),
                            ),
                        )
                    _response_json = _response.json()
                except JSONDecodeError:
                    raise ApiError(
                        status_code=_response.status_code, headers=dict(_response.headers), body=_response.text
                    )
                raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

            yield _stream()


class AsyncRawEntitiesClient:
    def __init__(self, *, client_wrapper: AsyncClientWrapper):
        self._client_wrapper = client_wrapper

    async def publish_entity(
        self,
        *,
        entity_id: typing.Optional[str] = OMIT,
        description: typing.Optional[str] = OMIT,
        is_live: typing.Optional[bool] = OMIT,
        created_time: typing.Optional[dt.datetime] = OMIT,
        expiry_time: typing.Optional[dt.datetime] = OMIT,
        no_expiry: typing.Optional[bool] = OMIT,
        status: typing.Optional[Status] = OMIT,
        location: typing.Optional[Location] = OMIT,
        location_uncertainty: typing.Optional[LocationUncertainty] = OMIT,
        geo_shape: typing.Optional[GeoShape] = OMIT,
        geo_details: typing.Optional[GeoDetails] = OMIT,
        aliases: typing.Optional[Aliases] = OMIT,
        tracked: typing.Optional[Tracked] = OMIT,
        correlation: typing.Optional[Correlation] = OMIT,
        mil_view: typing.Optional[MilView] = OMIT,
        ontology: typing.Optional[Ontology] = OMIT,
        sensors: typing.Optional[Sensors] = OMIT,
        payloads: typing.Optional[Payloads] = OMIT,
        power_state: typing.Optional[PowerState] = OMIT,
        provenance: typing.Optional[Provenance] = OMIT,
        overrides: typing.Optional[Overrides] = OMIT,
        indicators: typing.Optional[Indicators] = OMIT,
        target_priority: typing.Optional[TargetPriority] = OMIT,
        signal: typing.Optional[Signal] = OMIT,
        transponder_codes: typing.Optional[TransponderCodes] = OMIT,
        data_classification: typing.Optional[Classification] = OMIT,
        task_catalog: typing.Optional[TaskCatalog] = OMIT,
        media: typing.Optional[Media] = OMIT,
        relationships: typing.Optional[Relationships] = OMIT,
        visual_details: typing.Optional[VisualDetails] = OMIT,
        dimensions: typing.Optional[Dimensions] = OMIT,
        route_details: typing.Optional[RouteDetails] = OMIT,
        schedules: typing.Optional[Schedules] = OMIT,
        health: typing.Optional[Health] = OMIT,
        group_details: typing.Optional[GroupDetails] = OMIT,
        supplies: typing.Optional[Supplies] = OMIT,
        orbit: typing.Optional[Orbit] = OMIT,
        symbology: typing.Optional[Symbology] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncHttpResponse[Entity]:
        """
        Publish an entity for ingest into the Entities API. Entities created with this method are "owned" by the originator: other sources,
        such as the UI, may not edit or delete these entities. The server validates entities at API call time and
        returns an error if the entity is invalid.

        An entity ID must be provided when calling this endpoint. If the entity referenced by the entity ID does not exist
        then it will be created. Otherwise the entity will be updated. An entity will only be updated if its
        provenance.sourceUpdateTime is greater than the provenance.sourceUpdateTime of the existing entity.

        Parameters
        ----------
        entity_id : typing.Optional[str]
            A Globally Unique Identifier (GUID) for your entity. If this field is empty, the Entity Manager API
             automatically generates an ID when it creates the entity.

        description : typing.Optional[str]
            A human-readable entity description that's helpful for debugging purposes and human
             traceability. If this field is empty, the Entity Manager API generates one for you.

        is_live : typing.Optional[bool]
            Indicates the entity is active and should have a lifecycle state of CREATE or UPDATE.
             Set this field to true when publishing an entity.

        created_time : typing.Optional[dt.datetime]
            The time when the entity was first known to the entity producer. If this field is empty, the Entity Manager API uses the
             current timestamp of when the entity is first received.
             For example, when a drone is first powered on, it might report its startup time as the created time.
             The timestamp doesn't change for the lifetime of an entity.

        expiry_time : typing.Optional[dt.datetime]
            Future time that expires an entity and updates the is_live flag.
             For entities that are constantly updating, the expiry time also updates.
             In some cases, this may differ from is_live.
             Example: Entities with tasks exported to an external system must remain
             active even after they expire.
             This field is required when publishing a prepopulated entity.
             The expiry time must be in the future, but less than 30 days from the current time.

        no_expiry : typing.Optional[bool]
            Use noExpiry only when the entity contains information that should be available to other
             tasks or integrations beyond its immediate operational context. For example, use noExpiry
             for long-living geographical entities that maintain persistent relevance across multiple
             operations or tasks.

        status : typing.Optional[Status]
            Human-readable descriptions of what the entity is currently doing.

        location : typing.Optional[Location]
            Geospatial data related to the entity, including its position, kinematics, and orientation.

        location_uncertainty : typing.Optional[LocationUncertainty]
            Indicates uncertainty of the entity's position and kinematics.

        geo_shape : typing.Optional[GeoShape]
            Geospatial representation of the entity, including entities that cover an area rather than a fixed point.

        geo_details : typing.Optional[GeoDetails]
            Additional details on what the geospatial area or point represents, along with visual display details.

        aliases : typing.Optional[Aliases]
            Entity name displayed in the Lattice UI side panel. Also includes identifiers that other systems can use to reference the same entity.

        tracked : typing.Optional[Tracked]
            If this entity is tracked by another entity, this component contains data related to how it's being tracked.

        correlation : typing.Optional[Correlation]
            If this entity has been correlated or decorrelated to another one, this component contains information on the correlation or decorrelation.

        mil_view : typing.Optional[MilView]
            View of the entity.

        ontology : typing.Optional[Ontology]
            Ontology defines an entity's categorization in Lattice, and improves data retrieval and integration. Builds a standardized representation of the entity.

        sensors : typing.Optional[Sensors]
            Details an entity's available sensors.

        payloads : typing.Optional[Payloads]
            Details an entity's available payloads.

        power_state : typing.Optional[PowerState]
            Details the entity's power source.

        provenance : typing.Optional[Provenance]
            The primary data source provenance for this entity.

        overrides : typing.Optional[Overrides]
            Provenance of override data.

        indicators : typing.Optional[Indicators]
            Describes an entity's specific characteristics and the operations that can be performed on the entity.
             For example, "simulated" informs the operator that the entity is from a simulation, and "deletable"
             informs the operator (and system) that the delete operation is valid against the entity.

        target_priority : typing.Optional[TargetPriority]
            The prioritization associated with an entity, such as if it's a threat or a high-value target.

        signal : typing.Optional[Signal]
            Describes an entity's signal characteristics, primarily used when an entity is a signal of interest.

        transponder_codes : typing.Optional[TransponderCodes]
            A message describing any transponder codes associated with Mode 1, 2, 3, 4, 5, S interrogations. These are related to ADS-B modes.

        data_classification : typing.Optional[Classification]
            Describes an entity's security classification levels at an overall classification level and on a per
             field level.

        task_catalog : typing.Optional[TaskCatalog]
            A catalog of tasks that can be performed by an entity.

        media : typing.Optional[Media]
            Media associated with an entity, such as videos, images, or thumbnails.

        relationships : typing.Optional[Relationships]
            The relationships between this entity and other entities in the common operational picture (COP).

        visual_details : typing.Optional[VisualDetails]
            Visual details associated with the display of an entity in the client.

        dimensions : typing.Optional[Dimensions]
            Physical dimensions of the entity.

        route_details : typing.Optional[RouteDetails]
            Additional information about an entity's route.

        schedules : typing.Optional[Schedules]
            Schedules associated with this entity.

        health : typing.Optional[Health]
            Health metrics or connection status reported by the entity.

        group_details : typing.Optional[GroupDetails]
            Details for the group associated with this entity.

        supplies : typing.Optional[Supplies]
            Contains relevant supply information for the entity, such as fuel.

        orbit : typing.Optional[Orbit]
            Orbit information for space objects.

        symbology : typing.Optional[Symbology]
            Symbology/iconography for the entity respecting an existing standard.

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        AsyncHttpResponse[Entity]
            The request was valid and accepted.
        """
        _response = await self._client_wrapper.httpx_client.request(
            "api/v1/entities",
            method="PUT",
            json={
                "entityId": entity_id,
                "description": description,
                "isLive": is_live,
                "createdTime": created_time,
                "expiryTime": expiry_time,
                "noExpiry": no_expiry,
                "status": convert_and_respect_annotation_metadata(object_=status, annotation=Status, direction="write"),
                "location": convert_and_respect_annotation_metadata(
                    object_=location, annotation=Location, direction="write"
                ),
                "locationUncertainty": convert_and_respect_annotation_metadata(
                    object_=location_uncertainty, annotation=LocationUncertainty, direction="write"
                ),
                "geoShape": convert_and_respect_annotation_metadata(
                    object_=geo_shape, annotation=GeoShape, direction="write"
                ),
                "geoDetails": convert_and_respect_annotation_metadata(
                    object_=geo_details, annotation=GeoDetails, direction="write"
                ),
                "aliases": convert_and_respect_annotation_metadata(
                    object_=aliases, annotation=Aliases, direction="write"
                ),
                "tracked": convert_and_respect_annotation_metadata(
                    object_=tracked, annotation=Tracked, direction="write"
                ),
                "correlation": convert_and_respect_annotation_metadata(
                    object_=correlation, annotation=Correlation, direction="write"
                ),
                "milView": convert_and_respect_annotation_metadata(
                    object_=mil_view, annotation=MilView, direction="write"
                ),
                "ontology": convert_and_respect_annotation_metadata(
                    object_=ontology, annotation=Ontology, direction="write"
                ),
                "sensors": convert_and_respect_annotation_metadata(
                    object_=sensors, annotation=Sensors, direction="write"
                ),
                "payloads": convert_and_respect_annotation_metadata(
                    object_=payloads, annotation=Payloads, direction="write"
                ),
                "powerState": convert_and_respect_annotation_metadata(
                    object_=power_state, annotation=PowerState, direction="write"
                ),
                "provenance": convert_and_respect_annotation_metadata(
                    object_=provenance, annotation=Provenance, direction="write"
                ),
                "overrides": convert_and_respect_annotation_metadata(
                    object_=overrides, annotation=Overrides, direction="write"
                ),
                "indicators": convert_and_respect_annotation_metadata(
                    object_=indicators, annotation=Indicators, direction="write"
                ),
                "targetPriority": convert_and_respect_annotation_metadata(
                    object_=target_priority, annotation=TargetPriority, direction="write"
                ),
                "signal": convert_and_respect_annotation_metadata(object_=signal, annotation=Signal, direction="write"),
                "transponderCodes": convert_and_respect_annotation_metadata(
                    object_=transponder_codes, annotation=TransponderCodes, direction="write"
                ),
                "dataClassification": convert_and_respect_annotation_metadata(
                    object_=data_classification, annotation=Classification, direction="write"
                ),
                "taskCatalog": convert_and_respect_annotation_metadata(
                    object_=task_catalog, annotation=TaskCatalog, direction="write"
                ),
                "media": convert_and_respect_annotation_metadata(object_=media, annotation=Media, direction="write"),
                "relationships": convert_and_respect_annotation_metadata(
                    object_=relationships, annotation=Relationships, direction="write"
                ),
                "visualDetails": convert_and_respect_annotation_metadata(
                    object_=visual_details, annotation=VisualDetails, direction="write"
                ),
                "dimensions": convert_and_respect_annotation_metadata(
                    object_=dimensions, annotation=Dimensions, direction="write"
                ),
                "routeDetails": convert_and_respect_annotation_metadata(
                    object_=route_details, annotation=RouteDetails, direction="write"
                ),
                "schedules": convert_and_respect_annotation_metadata(
                    object_=schedules, annotation=Schedules, direction="write"
                ),
                "health": convert_and_respect_annotation_metadata(object_=health, annotation=Health, direction="write"),
                "groupDetails": convert_and_respect_annotation_metadata(
                    object_=group_details, annotation=GroupDetails, direction="write"
                ),
                "supplies": convert_and_respect_annotation_metadata(
                    object_=supplies, annotation=Supplies, direction="write"
                ),
                "orbit": convert_and_respect_annotation_metadata(object_=orbit, annotation=Orbit, direction="write"),
                "symbology": convert_and_respect_annotation_metadata(
                    object_=symbology, annotation=Symbology, direction="write"
                ),
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    Entity,
                    parse_obj_as(
                        type_=Entity,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            if _response.status_code == 400:
                raise BadRequestError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 401:
                raise UnauthorizedError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    async def get_entity(
        self, entity_id: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> AsyncHttpResponse[Entity]:
        """
        Parameters
        ----------
        entity_id : str
            ID of the entity to return

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        AsyncHttpResponse[Entity]
            Entity retrieval was successful
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"api/v1/entities/{jsonable_encoder(entity_id)}",
            method="GET",
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    Entity,
                    parse_obj_as(
                        type_=Entity,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            if _response.status_code == 400:
                raise BadRequestError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 401:
                raise UnauthorizedError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 404:
                raise NotFoundError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    async def override_entity(
        self,
        entity_id: str,
        field_path: str,
        *,
        entity: typing.Optional[Entity] = OMIT,
        provenance: typing.Optional[Provenance] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncHttpResponse[Entity]:
        """
        Only fields marked with overridable can be overridden. Please refer to our documentation to see the comprehensive
        list of fields that can be overridden. The entity in the request body should only have a value set on the field
        specified in the field path parameter. Field paths are rooted in the base entity object and must be represented
        using lower_snake_case. Do not include "entity" in the field path.

        Note that overrides are applied in an eventually consistent manner. If multiple overrides are created
        concurrently for the same field path, the last writer wins.

        Parameters
        ----------
        entity_id : str
            The unique ID of the entity to override

        field_path : str
            fieldPath to override

        entity : typing.Optional[Entity]
            The entity containing the overridden fields. The service will extract the overridable fields from
            the object and ignore all other fields.

        provenance : typing.Optional[Provenance]
            Additional information about the source of the override.

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        AsyncHttpResponse[Entity]
            The Entities API accepts the override.
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"api/v1/entities/{jsonable_encoder(entity_id)}/override/{jsonable_encoder(field_path)}",
            method="PUT",
            json={
                "entity": convert_and_respect_annotation_metadata(object_=entity, annotation=Entity, direction="write"),
                "provenance": convert_and_respect_annotation_metadata(
                    object_=provenance, annotation=Provenance, direction="write"
                ),
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    Entity,
                    parse_obj_as(
                        type_=Entity,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            if _response.status_code == 400:
                raise BadRequestError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 401:
                raise UnauthorizedError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 404:
                raise NotFoundError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    async def remove_entity_override(
        self, entity_id: str, field_path: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> AsyncHttpResponse[Entity]:
        """
        This operation clears the override value from the specified field path on the entity.

        Parameters
        ----------
        entity_id : str
            The unique ID of the entity to undo an override from.

        field_path : str
            The fieldPath to clear overrides from.

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        AsyncHttpResponse[Entity]
            The removal of entity override was successful.
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"api/v1/entities/{jsonable_encoder(entity_id)}/override/{jsonable_encoder(field_path)}",
            method="DELETE",
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    Entity,
                    parse_obj_as(
                        type_=Entity,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            if _response.status_code == 400:
                raise BadRequestError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 401:
                raise UnauthorizedError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 404:
                raise NotFoundError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    async def long_poll_entity_events(
        self,
        *,
        session_token: str,
        batch_size: typing.Optional[int] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncHttpResponse[EntityEventResponse]:
        """
        This is a long polling API that will first return all pre-existing data and then return all new data as
        it becomes available. If you want to start a new polling session then open a request with an empty
        'sessionToken' in the request body. The server will return a new session token in the response.
        If you want to retrieve the next batch of results from an existing polling session then send the session
        token you received from the server in the request body. If no new data is available then the server will
        hold the connection open for up to 5 minutes. After the 5 minute timeout period, the server will close the
        connection with no results and you may resume polling with the same session token. If your session falls behind
        more than 3x the total number of entities in the environment, the server will terminate your session.
        In this case you must start a new session by sending a request with an empty session token.

        Parameters
        ----------
        session_token : str
            Long-poll session identifier. Leave empty to start a new polling session.

        batch_size : typing.Optional[int]
            Maximum size of response batch. Defaults to 100. Must be between 1 and 2000 (inclusive).

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        AsyncHttpResponse[EntityEventResponse]
            Entity event batch retrieval was successful
        """
        _response = await self._client_wrapper.httpx_client.request(
            "api/v1/entities/events",
            method="POST",
            json={
                "sessionToken": session_token,
                "batchSize": batch_size,
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    EntityEventResponse,
                    parse_obj_as(
                        type_=EntityEventResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            if _response.status_code == 400:
                raise BadRequestError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 401:
                raise UnauthorizedError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 404:
                raise NotFoundError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 408:
                raise RequestTimeoutError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 429:
                raise TooManyRequestsError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    @contextlib.asynccontextmanager
    async def stream_entities(
        self,
        *,
        heartbeat_interval_ms: typing.Optional[int] = OMIT,
        pre_existing_only: typing.Optional[bool] = OMIT,
        components_to_include: typing.Optional[typing.Sequence[str]] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> typing.AsyncIterator[AsyncHttpResponse[typing.AsyncIterator[StreamEntitiesResponse]]]:
        """
        Establishes a persistent connection to stream entity events as they occur.

        Parameters
        ----------
        heartbeat_interval_ms : typing.Optional[int]
            at what interval to send heartbeat events, defaults to 30s.

        pre_existing_only : typing.Optional[bool]
            only stream pre-existing entities in the environment and then close the connection, defaults to false.

        components_to_include : typing.Optional[typing.Sequence[str]]
            list of components to include, leave empty to include all components.

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Yields
        ------
        typing.AsyncIterator[AsyncHttpResponse[typing.AsyncIterator[StreamEntitiesResponse]]]
            Returns all pre-existing data and then return all new data as they become available.
        """
        async with self._client_wrapper.httpx_client.stream(
            "api/v1/entities/stream",
            method="POST",
            json={
                "heartbeatIntervalMS": heartbeat_interval_ms,
                "preExistingOnly": pre_existing_only,
                "componentsToInclude": components_to_include,
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        ) as _response:

            async def _stream() -> AsyncHttpResponse[typing.AsyncIterator[StreamEntitiesResponse]]:
                try:
                    if 200 <= _response.status_code < 300:

                        async def _iter():
                            _event_source = httpx_sse.EventSource(_response)
                            async for _sse in _event_source.aiter_sse():
                                if _sse.data == None:
                                    return
                                try:
                                    yield typing.cast(
                                        StreamEntitiesResponse,
                                        parse_obj_as(
                                            type_=StreamEntitiesResponse,  # type: ignore
                                            object_=json.loads(_sse.data),
                                        ),
                                    )
                                except Exception:
                                    pass
                            return

                        return AsyncHttpResponse(response=_response, data=_iter())
                    await _response.aread()
                    if _response.status_code == 400:
                        raise BadRequestError(
                            headers=dict(_response.headers),
                            body=typing.cast(
                                typing.Optional[typing.Any],
                                parse_obj_as(
                                    type_=typing.Optional[typing.Any],  # type: ignore
                                    object_=_response.json(),
                                ),
                            ),
                        )
                    if _response.status_code == 401:
                        raise UnauthorizedError(
                            headers=dict(_response.headers),
                            body=typing.cast(
                                typing.Optional[typing.Any],
                                parse_obj_as(
                                    type_=typing.Optional[typing.Any],  # type: ignore
                                    object_=_response.json(),
                                ),
                            ),
                        )
                    _response_json = _response.json()
                except JSONDecodeError:
                    raise ApiError(
                        status_code=_response.status_code, headers=dict(_response.headers), body=_response.text
                    )
                raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

            yield await _stream()
