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

import typing
from ..core.client_wrapper import SyncClientWrapper
from .types.create_resolved_project_entity_request import CreateResolvedProjectEntityRequest
from ..core.request_options import RequestOptions
from .types.single_project_entity_response import SingleProjectEntityResponse
from ..core.jsonable_encoder import jsonable_encoder
from ..core.serialization import convert_and_respect_annotation_metadata
from ..core.pydantic_utilities import parse_obj_as
from ..shared_errors.errors.bad_request import BadRequest
from ..shared_errors.types.bad_request_response import BadRequestResponse
from ..shared_errors.errors.unauthorized import Unauthorized
from ..shared_errors.types.unauthorized_response import UnauthorizedResponse
from ..shared_errors.errors.not_found import NotFound
from ..shared_errors.types.not_found_response import NotFoundResponse
from ..shared_errors.errors.method_not_allowed import MethodNotAllowed
from ..shared_errors.types.method_not_allowed_response import MethodNotAllowedResponse
from ..shared_errors.errors.rate_limit_exceeded import RateLimitExceeded
from ..shared_errors.types.rate_limit_response import RateLimitResponse
from ..shared_errors.errors.internal_server_error import InternalServerError
from ..shared_errors.types.internal_server_error_response import InternalServerErrorResponse
from json.decoder import JSONDecodeError
from ..core.api_error import ApiError
from .types.project_entities_filter import ProjectEntitiesFilter
from .types.project_entities_response import ProjectEntitiesResponse
from .types.resolution_attributes import ResolutionAttributes
from .types.project_entity_id_response import ProjectEntityIdResponse
from .types.save_project_entity_body import SaveProjectEntityBody
from .types.sort_order import SortOrder
from .types.project_risk_changes_response import ProjectRiskChangesResponse
from ..shared_errors.errors.unprocessable_content import UnprocessableContent
from ..shared_errors.types.unprocessable_content_response import UnprocessableContentResponse
from .types.project_entity_risk_changes_response import ProjectEntityRiskChangesResponse
from ..generated_types.types.risk import Risk
from ..generated_types.types.country import Country
from ..supply_chain.types.upstream_trade_traversal_response import UpstreamTradeTraversalResponse
from .types.project_entity_risk_summary_filters import ProjectEntityRiskSummaryFilters
from .types.project_entity_risk_summary_response import ProjectEntityRiskSummaryResponse
from .types.project_entity_supply_chain_summary_response import ProjectEntitySupplyChainSummaryResponse
from ..core.client_wrapper import AsyncClientWrapper

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


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

    def create_project_entity(
        self,
        project_id: str,
        *,
        request: CreateResolvedProjectEntityRequest,
        enable_llm_clean: typing.Optional[bool] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> SingleProjectEntityResponse:
        """
        The resolution endpoints allow users to search for matching entities against a provided list of attributes. The endpoint is similar to the search endpoint, except it's tuned to only return the best match so the client doesn't need to do as much or any post-processing work to filter down results.

        Parameters
        ----------
        project_id : str

        request : CreateResolvedProjectEntityRequest

        enable_llm_clean : typing.Optional[bool]
            Whether to enable LLM-based data cleaning to remove noise and standardize entity attributes. Defaults to true if not supplied. Set to false to disable LLM cleaning.

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

        Returns
        -------
        SingleProjectEntityResponse

        Examples
        --------
        from sayari import Sayari
        from sayari.project_entity import CreateResolvedProjectEntityRequest

        client = Sayari(
            client_id="YOUR_CLIENT_ID",
            client_secret="YOUR_CLIENT_SECRET",
        )
        client.project_entity.create_project_entity(
            project_id="YVB88Y",
            request=CreateResolvedProjectEntityRequest(
                name=["VTB Bank"],
                country=["RUS"],
                address=["Moscow"],
                identifier=["253400V1H6ART1UQ0N98"],
                profile="corporate",
            ),
        )
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v1/projects/{jsonable_encoder(project_id)}/entities/create",
            method="POST",
            params={
                "enable_llm_clean": enable_llm_clean,
            },
            json=convert_and_respect_annotation_metadata(
                object_=request, annotation=CreateResolvedProjectEntityRequest, direction="write"
            ),
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                return typing.cast(
                    SingleProjectEntityResponse,
                    parse_obj_as(
                        type_=SingleProjectEntityResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
            if _response.status_code == 400:
                raise BadRequest(
                    typing.cast(
                        BadRequestResponse,
                        parse_obj_as(
                            type_=BadRequestResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 401:
                raise Unauthorized(
                    typing.cast(
                        UnauthorizedResponse,
                        parse_obj_as(
                            type_=UnauthorizedResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 404:
                raise NotFound(
                    typing.cast(
                        NotFoundResponse,
                        parse_obj_as(
                            type_=NotFoundResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 405:
                raise MethodNotAllowed(
                    typing.cast(
                        MethodNotAllowedResponse,
                        parse_obj_as(
                            type_=MethodNotAllowedResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 429:
                raise RateLimitExceeded(
                    typing.cast(
                        RateLimitResponse,
                        parse_obj_as(
                            type_=RateLimitResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 500:
                raise InternalServerError(
                    typing.cast(
                        InternalServerErrorResponse,
                        parse_obj_as(
                            type_=InternalServerErrorResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    def get_project_entities(
        self,
        project_id: str,
        *,
        next: typing.Optional[str] = None,
        prev: typing.Optional[str] = None,
        limit: typing.Optional[int] = None,
        filter: typing.Optional[ProjectEntitiesFilter] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> ProjectEntitiesResponse:
        """
        Retrieves a list of entities for a specific project with pagination support.

        **Response Formats:**
        - **JSON** (default): Returns structured data with nested objects
        - **CSV**: Returns tabular data with dynamic columns for attributes and risk categories

        **CSV Format:**
        The CSV response includes dynamic columns based on the data:
        - `attribute_{field_name}`: Dynamic columns for each attribute field found in the data
        - `risk_category_{category_id}`: Dynamic columns for each risk category found in the data
        - Standard columns: project_id, project_entity_id, label, project_entity_url, upload_ids, strength, countries, tags, case_status, created_at, match_count, upstream_products, upstream_risk_factors, upstream_countries

        Use the `Accept: text/csv` header to request CSV format.

        Parameters
        ----------
        project_id : str

        next : typing.Optional[str]
            The pagination token for the next page of projects.

        prev : typing.Optional[str]
            The pagination token for the previous page of projects.

        limit : typing.Optional[int]
            Limit total values returned for projects. Defaults to 100. Max 100.

        filter : typing.Optional[ProjectEntitiesFilter]
            Filter the project entities. Supports both dot notation (e.g., 'filter.attribute.name') and bracket notation (e.g., 'filter[attribute][name]') for nested field filtering.

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

        Returns
        -------
        ProjectEntitiesResponse

        Examples
        --------
        from sayari import Sayari

        client = Sayari(
            client_id="YOUR_CLIENT_ID",
            client_secret="YOUR_CLIENT_SECRET",
        )
        client.project_entity.get_project_entities(
            project_id="YVB88Y",
        )
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v1/projects/{jsonable_encoder(project_id)}/entities",
            method="GET",
            params={
                "next": next,
                "prev": prev,
                "limit": limit,
                "filter": convert_and_respect_annotation_metadata(
                    object_=filter, annotation=ProjectEntitiesFilter, direction="write"
                ),
            },
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                return typing.cast(
                    ProjectEntitiesResponse,
                    parse_obj_as(
                        type_=ProjectEntitiesResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
            if _response.status_code == 400:
                raise BadRequest(
                    typing.cast(
                        BadRequestResponse,
                        parse_obj_as(
                            type_=BadRequestResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 401:
                raise Unauthorized(
                    typing.cast(
                        UnauthorizedResponse,
                        parse_obj_as(
                            type_=UnauthorizedResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 404:
                raise NotFound(
                    typing.cast(
                        NotFoundResponse,
                        parse_obj_as(
                            type_=NotFoundResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 405:
                raise MethodNotAllowed(
                    typing.cast(
                        MethodNotAllowedResponse,
                        parse_obj_as(
                            type_=MethodNotAllowedResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 429:
                raise RateLimitExceeded(
                    typing.cast(
                        RateLimitResponse,
                        parse_obj_as(
                            type_=RateLimitResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 500:
                raise InternalServerError(
                    typing.cast(
                        InternalServerErrorResponse,
                        parse_obj_as(
                            type_=InternalServerErrorResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    def get_project_entity(
        self, project_id: str, project_entity_id: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> SingleProjectEntityResponse:
        """
        Retrieves a specific entity in a project.

        Parameters
        ----------
        project_id : str

        project_entity_id : str

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

        Returns
        -------
        SingleProjectEntityResponse

        Examples
        --------
        from sayari import Sayari

        client = Sayari(
            client_id="YOUR_CLIENT_ID",
            client_secret="YOUR_CLIENT_SECRET",
        )
        client.project_entity.get_project_entity(
            project_id="project_id",
            project_entity_id="project_entity_id",
        )
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v1/projects/{jsonable_encoder(project_id)}/entities/{jsonable_encoder(project_entity_id)}",
            method="GET",
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                return typing.cast(
                    SingleProjectEntityResponse,
                    parse_obj_as(
                        type_=SingleProjectEntityResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
            if _response.status_code == 400:
                raise BadRequest(
                    typing.cast(
                        BadRequestResponse,
                        parse_obj_as(
                            type_=BadRequestResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 401:
                raise Unauthorized(
                    typing.cast(
                        UnauthorizedResponse,
                        parse_obj_as(
                            type_=UnauthorizedResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 404:
                raise NotFound(
                    typing.cast(
                        NotFoundResponse,
                        parse_obj_as(
                            type_=NotFoundResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 405:
                raise MethodNotAllowed(
                    typing.cast(
                        MethodNotAllowedResponse,
                        parse_obj_as(
                            type_=MethodNotAllowedResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 429:
                raise RateLimitExceeded(
                    typing.cast(
                        RateLimitResponse,
                        parse_obj_as(
                            type_=RateLimitResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 500:
                raise InternalServerError(
                    typing.cast(
                        InternalServerErrorResponse,
                        parse_obj_as(
                            type_=InternalServerErrorResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    def delete_project_entity(
        self, project_id: str, project_entity_id: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> None:
        """
        Deletes a project entity.

        Parameters
        ----------
        project_id : str

        project_entity_id : str

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

        Returns
        -------
        None

        Examples
        --------
        from sayari import Sayari

        client = Sayari(
            client_id="YOUR_CLIENT_ID",
            client_secret="YOUR_CLIENT_SECRET",
        )
        client.project_entity.delete_project_entity(
            project_id="project_id",
            project_entity_id="project_entity_id",
        )
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v1/projects/{jsonable_encoder(project_id)}/entities/{jsonable_encoder(project_entity_id)}",
            method="DELETE",
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                return
            if _response.status_code == 400:
                raise BadRequest(
                    typing.cast(
                        BadRequestResponse,
                        parse_obj_as(
                            type_=BadRequestResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 401:
                raise Unauthorized(
                    typing.cast(
                        UnauthorizedResponse,
                        parse_obj_as(
                            type_=UnauthorizedResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 404:
                raise NotFound(
                    typing.cast(
                        NotFoundResponse,
                        parse_obj_as(
                            type_=NotFoundResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 405:
                raise MethodNotAllowed(
                    typing.cast(
                        MethodNotAllowedResponse,
                        parse_obj_as(
                            type_=MethodNotAllowedResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 429:
                raise RateLimitExceeded(
                    typing.cast(
                        RateLimitResponse,
                        parse_obj_as(
                            type_=RateLimitResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 500:
                raise InternalServerError(
                    typing.cast(
                        InternalServerErrorResponse,
                        parse_obj_as(
                            type_=InternalServerErrorResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    def delete_project_entity_match(
        self,
        project_id: str,
        project_entity_id: str,
        match_id: str,
        *,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> None:
        """
        Deletes a specific project entity match.

        Parameters
        ----------
        project_id : str

        project_entity_id : str

        match_id : str

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

        Returns
        -------
        None

        Examples
        --------
        from sayari import Sayari

        client = Sayari(
            client_id="YOUR_CLIENT_ID",
            client_secret="YOUR_CLIENT_SECRET",
        )
        client.project_entity.delete_project_entity_match(
            project_id="project_id",
            project_entity_id="project_entity_id",
            match_id="match_id",
        )
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v1/projects/{jsonable_encoder(project_id)}/entities/{jsonable_encoder(project_entity_id)}/matches/{jsonable_encoder(match_id)}",
            method="DELETE",
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                return
            if _response.status_code == 400:
                raise BadRequest(
                    typing.cast(
                        BadRequestResponse,
                        parse_obj_as(
                            type_=BadRequestResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 401:
                raise Unauthorized(
                    typing.cast(
                        UnauthorizedResponse,
                        parse_obj_as(
                            type_=UnauthorizedResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 404:
                raise NotFound(
                    typing.cast(
                        NotFoundResponse,
                        parse_obj_as(
                            type_=NotFoundResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 405:
                raise MethodNotAllowed(
                    typing.cast(
                        MethodNotAllowedResponse,
                        parse_obj_as(
                            type_=MethodNotAllowedResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 429:
                raise RateLimitExceeded(
                    typing.cast(
                        RateLimitResponse,
                        parse_obj_as(
                            type_=RateLimitResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 500:
                raise InternalServerError(
                    typing.cast(
                        InternalServerErrorResponse,
                        parse_obj_as(
                            type_=InternalServerErrorResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    def project_entity_exists(
        self, project_id: str, *, request: ResolutionAttributes, request_options: typing.Optional[RequestOptions] = None
    ) -> ProjectEntityIdResponse:
        """
        Checks if a project entity with the given attributes already exists.

        Parameters
        ----------
        project_id : str

        request : ResolutionAttributes

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

        Returns
        -------
        ProjectEntityIdResponse

        Examples
        --------
        from sayari import Sayari
        from sayari.project_entity import ResolutionAttributes

        client = Sayari(
            client_id="YOUR_CLIENT_ID",
            client_secret="YOUR_CLIENT_SECRET",
        )
        client.project_entity.project_entity_exists(
            project_id="YVB88Y",
            request=ResolutionAttributes(
                name=["Example Company"],
                country=["USA"],
            ),
        )
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v1/projects/{jsonable_encoder(project_id)}/entities/exists",
            method="POST",
            json=convert_and_respect_annotation_metadata(
                object_=request, annotation=ResolutionAttributes, direction="write"
            ),
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                return typing.cast(
                    ProjectEntityIdResponse,
                    parse_obj_as(
                        type_=ProjectEntityIdResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
            if _response.status_code == 400:
                raise BadRequest(
                    typing.cast(
                        BadRequestResponse,
                        parse_obj_as(
                            type_=BadRequestResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 401:
                raise Unauthorized(
                    typing.cast(
                        UnauthorizedResponse,
                        parse_obj_as(
                            type_=UnauthorizedResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 404:
                raise NotFound(
                    typing.cast(
                        NotFoundResponse,
                        parse_obj_as(
                            type_=NotFoundResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 405:
                raise MethodNotAllowed(
                    typing.cast(
                        MethodNotAllowedResponse,
                        parse_obj_as(
                            type_=MethodNotAllowedResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 429:
                raise RateLimitExceeded(
                    typing.cast(
                        RateLimitResponse,
                        parse_obj_as(
                            type_=RateLimitResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 500:
                raise InternalServerError(
                    typing.cast(
                        InternalServerErrorResponse,
                        parse_obj_as(
                            type_=InternalServerErrorResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    def save_project_entity(
        self,
        project_id: str,
        *,
        request: SaveProjectEntityBody,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> ProjectEntityIdResponse:
        """
        Stores a project entity given entity IDs and a list of attributes.

        Parameters
        ----------
        project_id : str

        request : SaveProjectEntityBody

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

        Returns
        -------
        ProjectEntityIdResponse

        Examples
        --------
        from sayari import Sayari
        from sayari.project_entity import ResolutionAttributes, SaveProjectEntityBody

        client = Sayari(
            client_id="YOUR_CLIENT_ID",
            client_secret="YOUR_CLIENT_SECRET",
        )
        client.project_entity.save_project_entity(
            project_id="YVB88Y",
            request=SaveProjectEntityBody(
                entity_ids=["entity_id_1", "entity_id_2"],
                attributes=ResolutionAttributes(
                    name=["Example Company"],
                    country=["USA"],
                ),
                profile="corporate",
            ),
        )
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v1/projects/{jsonable_encoder(project_id)}/entities/save",
            method="POST",
            json=convert_and_respect_annotation_metadata(
                object_=request, annotation=SaveProjectEntityBody, direction="write"
            ),
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                return typing.cast(
                    ProjectEntityIdResponse,
                    parse_obj_as(
                        type_=ProjectEntityIdResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
            if _response.status_code == 400:
                raise BadRequest(
                    typing.cast(
                        BadRequestResponse,
                        parse_obj_as(
                            type_=BadRequestResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 401:
                raise Unauthorized(
                    typing.cast(
                        UnauthorizedResponse,
                        parse_obj_as(
                            type_=UnauthorizedResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 404:
                raise NotFound(
                    typing.cast(
                        NotFoundResponse,
                        parse_obj_as(
                            type_=NotFoundResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 405:
                raise MethodNotAllowed(
                    typing.cast(
                        MethodNotAllowedResponse,
                        parse_obj_as(
                            type_=MethodNotAllowedResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 429:
                raise RateLimitExceeded(
                    typing.cast(
                        RateLimitResponse,
                        parse_obj_as(
                            type_=RateLimitResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 500:
                raise InternalServerError(
                    typing.cast(
                        InternalServerErrorResponse,
                        parse_obj_as(
                            type_=InternalServerErrorResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    def get_project_risk_changes(
        self,
        project_id: str,
        *,
        limit: typing.Optional[int] = None,
        next: typing.Optional[str] = None,
        prev: typing.Optional[str] = None,
        sort_date: typing.Optional[SortOrder] = None,
        filter_from: typing.Optional[str] = None,
        filter_to: typing.Optional[str] = None,
        filter_risk_factor: typing.Optional[typing.Sequence[str]] = None,
        filter_risk_category: typing.Optional[typing.Sequence[str]] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> ProjectRiskChangesResponse:
        """
        Retrieves the risk changes for all project entities in a project.

        Parameters
        ----------
        project_id : str

        limit : typing.Optional[int]
            The maximum number of risk changes to return. Default is 100.

        next : typing.Optional[str]
            Token to retrieve the next page of risk changes

        prev : typing.Optional[str]
            Token to retrieve the previous page of risk changes

        sort_date : typing.Optional[SortOrder]
            Sort by timestamp in ascending or descending order. Default is desc.

        filter_from : typing.Optional[str]
            Filter risk changes from the provided date

        filter_to : typing.Optional[str]
            Filter risk changes up to the provided date

        filter_risk_factor : typing.Optional[typing.Sequence[str]]
            Filter risk changes for the provided risk factors

        filter_risk_category : typing.Optional[typing.Sequence[str]]
            Filter risk changes for risk factors from the provided risk categories

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

        Returns
        -------
        ProjectRiskChangesResponse

        Examples
        --------
        from sayari import Sayari

        client = Sayari(
            client_id="YOUR_CLIENT_ID",
            client_secret="YOUR_CLIENT_SECRET",
        )
        client.project_entity.get_project_risk_changes(
            project_id="YVB88Y",
        )
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v1/projects/{jsonable_encoder(project_id)}/entities/changes/risk",
            method="GET",
            params={
                "limit": limit,
                "next": next,
                "prev": prev,
                "sort.date": sort_date,
                "filter.from": filter_from,
                "filter.to": filter_to,
                "filter.risk_factor": filter_risk_factor,
                "filter.risk_category": filter_risk_category,
            },
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                return typing.cast(
                    ProjectRiskChangesResponse,
                    parse_obj_as(
                        type_=ProjectRiskChangesResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
            if _response.status_code == 400:
                raise BadRequest(
                    typing.cast(
                        BadRequestResponse,
                        parse_obj_as(
                            type_=BadRequestResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 401:
                raise Unauthorized(
                    typing.cast(
                        UnauthorizedResponse,
                        parse_obj_as(
                            type_=UnauthorizedResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 404:
                raise NotFound(
                    typing.cast(
                        NotFoundResponse,
                        parse_obj_as(
                            type_=NotFoundResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 405:
                raise MethodNotAllowed(
                    typing.cast(
                        MethodNotAllowedResponse,
                        parse_obj_as(
                            type_=MethodNotAllowedResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 422:
                raise UnprocessableContent(
                    typing.cast(
                        UnprocessableContentResponse,
                        parse_obj_as(
                            type_=UnprocessableContentResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 429:
                raise RateLimitExceeded(
                    typing.cast(
                        RateLimitResponse,
                        parse_obj_as(
                            type_=RateLimitResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 500:
                raise InternalServerError(
                    typing.cast(
                        InternalServerErrorResponse,
                        parse_obj_as(
                            type_=InternalServerErrorResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    def get_project_entity_risk_changes(
        self,
        project_id: str,
        project_entity_id: str,
        *,
        limit: typing.Optional[int] = None,
        next: typing.Optional[str] = None,
        prev: typing.Optional[str] = None,
        sort_date: typing.Optional[SortOrder] = None,
        filter_from: typing.Optional[str] = None,
        filter_to: typing.Optional[str] = None,
        filter_risk_factor: typing.Optional[typing.Sequence[str]] = None,
        filter_risk_category: typing.Optional[typing.Sequence[str]] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> ProjectEntityRiskChangesResponse:
        """
        Retrieves the risk changes for a single project entity.

        Parameters
        ----------
        project_id : str

        project_entity_id : str

        limit : typing.Optional[int]
            The maximum number of risk changes to return. Default is 100.

        next : typing.Optional[str]
            Token to retrieve the next page of risk changes

        prev : typing.Optional[str]
            Token to retrieve the previous page of risk changes

        sort_date : typing.Optional[SortOrder]
            Sort by timestamp in ascending or descending order. Default is desc.

        filter_from : typing.Optional[str]
            Filter risk changes from the provided date

        filter_to : typing.Optional[str]
            Filter risk changes up to the provided date

        filter_risk_factor : typing.Optional[typing.Sequence[str]]
            Filter risk changes for the provided risk factors

        filter_risk_category : typing.Optional[typing.Sequence[str]]
            Filter risk changes for risk factors from the provided risk categories

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

        Returns
        -------
        ProjectEntityRiskChangesResponse

        Examples
        --------
        from sayari import Sayari

        client = Sayari(
            client_id="YOUR_CLIENT_ID",
            client_secret="YOUR_CLIENT_SECRET",
        )
        client.project_entity.get_project_entity_risk_changes(
            project_id="YVB88Y",
            project_entity_id="52z4Wa",
        )
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v1/projects/{jsonable_encoder(project_id)}/entities/{jsonable_encoder(project_entity_id)}/changes/risk",
            method="GET",
            params={
                "limit": limit,
                "next": next,
                "prev": prev,
                "sort.date": sort_date,
                "filter.from": filter_from,
                "filter.to": filter_to,
                "filter.risk_factor": filter_risk_factor,
                "filter.risk_category": filter_risk_category,
            },
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                return typing.cast(
                    ProjectEntityRiskChangesResponse,
                    parse_obj_as(
                        type_=ProjectEntityRiskChangesResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
            if _response.status_code == 400:
                raise BadRequest(
                    typing.cast(
                        BadRequestResponse,
                        parse_obj_as(
                            type_=BadRequestResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 401:
                raise Unauthorized(
                    typing.cast(
                        UnauthorizedResponse,
                        parse_obj_as(
                            type_=UnauthorizedResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 404:
                raise NotFound(
                    typing.cast(
                        NotFoundResponse,
                        parse_obj_as(
                            type_=NotFoundResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 405:
                raise MethodNotAllowed(
                    typing.cast(
                        MethodNotAllowedResponse,
                        parse_obj_as(
                            type_=MethodNotAllowedResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 422:
                raise UnprocessableContent(
                    typing.cast(
                        UnprocessableContentResponse,
                        parse_obj_as(
                            type_=UnprocessableContentResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 429:
                raise RateLimitExceeded(
                    typing.cast(
                        RateLimitResponse,
                        parse_obj_as(
                            type_=RateLimitResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 500:
                raise InternalServerError(
                    typing.cast(
                        InternalServerErrorResponse,
                        parse_obj_as(
                            type_=InternalServerErrorResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    def delete_project_risk_changes(
        self, project_id: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> None:
        """
        Dismiss risk changes for all project entities in a project.

        Parameters
        ----------
        project_id : str

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

        Returns
        -------
        None

        Examples
        --------
        from sayari import Sayari

        client = Sayari(
            client_id="YOUR_CLIENT_ID",
            client_secret="YOUR_CLIENT_SECRET",
        )
        client.project_entity.delete_project_risk_changes(
            project_id="project_id",
        )
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v1/projects/{jsonable_encoder(project_id)}/entities/changes/risk",
            method="DELETE",
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                return
            if _response.status_code == 400:
                raise BadRequest(
                    typing.cast(
                        BadRequestResponse,
                        parse_obj_as(
                            type_=BadRequestResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 401:
                raise Unauthorized(
                    typing.cast(
                        UnauthorizedResponse,
                        parse_obj_as(
                            type_=UnauthorizedResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 404:
                raise NotFound(
                    typing.cast(
                        NotFoundResponse,
                        parse_obj_as(
                            type_=NotFoundResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 405:
                raise MethodNotAllowed(
                    typing.cast(
                        MethodNotAllowedResponse,
                        parse_obj_as(
                            type_=MethodNotAllowedResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 429:
                raise RateLimitExceeded(
                    typing.cast(
                        RateLimitResponse,
                        parse_obj_as(
                            type_=RateLimitResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 500:
                raise InternalServerError(
                    typing.cast(
                        InternalServerErrorResponse,
                        parse_obj_as(
                            type_=InternalServerErrorResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    def delete_project_entity_risk_changes(
        self, project_id: str, project_entity_id: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> None:
        """
        Dismiss risk changes for a single project entity.

        Parameters
        ----------
        project_id : str

        project_entity_id : str

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

        Returns
        -------
        None

        Examples
        --------
        from sayari import Sayari

        client = Sayari(
            client_id="YOUR_CLIENT_ID",
            client_secret="YOUR_CLIENT_SECRET",
        )
        client.project_entity.delete_project_entity_risk_changes(
            project_id="project_id",
            project_entity_id="project_entity_id",
        )
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v1/projects/{jsonable_encoder(project_id)}/entities/{jsonable_encoder(project_entity_id)}/changes/risk",
            method="DELETE",
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                return
            if _response.status_code == 400:
                raise BadRequest(
                    typing.cast(
                        BadRequestResponse,
                        parse_obj_as(
                            type_=BadRequestResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 401:
                raise Unauthorized(
                    typing.cast(
                        UnauthorizedResponse,
                        parse_obj_as(
                            type_=UnauthorizedResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 404:
                raise NotFound(
                    typing.cast(
                        NotFoundResponse,
                        parse_obj_as(
                            type_=NotFoundResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 405:
                raise MethodNotAllowed(
                    typing.cast(
                        MethodNotAllowedResponse,
                        parse_obj_as(
                            type_=MethodNotAllowedResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 429:
                raise RateLimitExceeded(
                    typing.cast(
                        RateLimitResponse,
                        parse_obj_as(
                            type_=RateLimitResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 500:
                raise InternalServerError(
                    typing.cast(
                        InternalServerErrorResponse,
                        parse_obj_as(
                            type_=InternalServerErrorResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    def project_entity_supply_chain(
        self,
        project_id: str,
        project_entity_id: str,
        *,
        product: typing.Optional[typing.Sequence[str]] = None,
        not_product: typing.Optional[typing.Sequence[str]] = None,
        risk: typing.Optional[typing.Sequence[Risk]] = None,
        not_risk: typing.Optional[typing.Sequence[Risk]] = None,
        countries: typing.Optional[typing.Sequence[Country]] = None,
        not_countries: typing.Optional[typing.Sequence[Country]] = None,
        shipment_country: typing.Optional[typing.Sequence[Country]] = None,
        not_shipment_country: typing.Optional[typing.Sequence[Country]] = None,
        tier_1_shipment_country: typing.Optional[typing.Sequence[Country]] = None,
        tier_2_shipment_country: typing.Optional[typing.Sequence[Country]] = None,
        tier_3_shipment_country: typing.Optional[typing.Sequence[Country]] = None,
        tier_4_shipment_country: typing.Optional[typing.Sequence[Country]] = None,
        tier_5_shipment_country: typing.Optional[typing.Sequence[Country]] = None,
        component: typing.Optional[typing.Sequence[str]] = None,
        not_component: typing.Optional[typing.Sequence[str]] = None,
        min_date: typing.Optional[str] = None,
        max_date: typing.Optional[str] = None,
        max_depth: typing.Optional[int] = None,
        limit: typing.Optional[int] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> UpstreamTradeTraversalResponse:
        """
        Execute a traversal of the upstream trade network (supply chain) for all matched entities of a project entity, returning a set of entities and edges between them.

        Parameters
        ----------
        project_id : str
            The project Identifier

        project_entity_id : str
            The project entity Identifier

        product : typing.Optional[typing.Sequence[str]]
            Product root edge filter. Filters results to include only trade relationships where the associated component is part of the specified product's blueprint or is a sub-component of that product.

        not_product : typing.Optional[typing.Sequence[str]]
            Product root edge filter. Filters results to exclude any trade relationships where the associated component is part of the specified product's blueprint or is a sub-component of that product.

        risk : typing.Optional[typing.Sequence[Risk]]
            Risk leaf node filter. Only return supply chains that end with a supplier that has 1+ of the specified risk factors.

        not_risk : typing.Optional[typing.Sequence[Risk]]
            Risk leaf node filter. Only return supply chains that end with a supplier that has none of the specified risk factors.

        countries : typing.Optional[typing.Sequence[Country]]
            Country leaf node filter. Only return supply chains that end with a supplier in 1+ of the specified countries.

        not_countries : typing.Optional[typing.Sequence[Country]]
            Country leaf node filter. Only return supply chains that end with a supplier in none of the specified countries.

        shipment_country : typing.Optional[typing.Sequence[Country]]
            Filters supply chain paths where 1+ shipment country from any tier matches the provided values.

        not_shipment_country : typing.Optional[typing.Sequence[Country]]
            Filters supply chain paths where none of the shipment countries from any tier matches the provided values.

        tier_1_shipment_country : typing.Optional[typing.Sequence[Country]]
            Filters supply chain paths where 1+ shipment country from tier 1 matches the provided values.

        tier_2_shipment_country : typing.Optional[typing.Sequence[Country]]
            Filters supply chain paths where 1+ shipment country from tier 2 matches the provided values.

        tier_3_shipment_country : typing.Optional[typing.Sequence[Country]]
            Filters supply chain paths where 1+ shipment country from tier 3 matches the provided values.

        tier_4_shipment_country : typing.Optional[typing.Sequence[Country]]
            Filters supply chain paths where 1+ shipment country from tier 4 matches the provided values.

        tier_5_shipment_country : typing.Optional[typing.Sequence[Country]]
            Filters supply chain paths where 1+ shipment country from tier 5 matches the provided values.

        component : typing.Optional[typing.Sequence[str]]
            Component edge filter. Only return supply chains that contain at least one edge with 1+ of the specified HS codes.

        not_component : typing.Optional[typing.Sequence[str]]
            Component edge filter. Only return supply chains that contain no edges with any of the specified HS codes.

        min_date : typing.Optional[str]
            Minimum date edge filter in <YYYY-MM-DD> format. Only return supply chains with edge dates that are greater than or equal to this date.

        max_date : typing.Optional[str]
            Maximum date edge filter in <YYYY-MM-DD> format. Only return supply chains with edge dates that are less than or equal to this date.

        max_depth : typing.Optional[int]
            The maximum depth of the traversal, from 1 to 4 inclusive. Default is 4. Reduce if query is timing out.

        limit : typing.Optional[int]
            The maximum number of results to return. Default is no limit.

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

        Returns
        -------
        UpstreamTradeTraversalResponse

        Examples
        --------
        from sayari import Sayari

        client = Sayari(
            client_id="YOUR_CLIENT_ID",
            client_secret="YOUR_CLIENT_SECRET",
        )
        client.project_entity.project_entity_supply_chain(
            project_id="0n4473",
            project_entity_id="yebNPJ",
            product=["6004"],
            limit=1,
        )
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v1/projects/{jsonable_encoder(project_id)}/entities/{jsonable_encoder(project_entity_id)}/supply_chain/upstream",
            method="GET",
            params={
                "product": product,
                "-product": not_product,
                "risk": risk,
                "-risk": not_risk,
                "countries": countries,
                "-countries": not_countries,
                "shipment_country": shipment_country,
                "-shipment_country": not_shipment_country,
                "tier1_shipment_country": tier_1_shipment_country,
                "tier2_shipment_country": tier_2_shipment_country,
                "tier3_shipment_country": tier_3_shipment_country,
                "tier4_shipment_country": tier_4_shipment_country,
                "tier5_shipment_country": tier_5_shipment_country,
                "component": component,
                "-component": not_component,
                "min_date": min_date,
                "max_date": max_date,
                "max_depth": max_depth,
                "limit": limit,
            },
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                return typing.cast(
                    UpstreamTradeTraversalResponse,
                    parse_obj_as(
                        type_=UpstreamTradeTraversalResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
            if _response.status_code == 400:
                raise BadRequest(
                    typing.cast(
                        BadRequestResponse,
                        parse_obj_as(
                            type_=BadRequestResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 401:
                raise Unauthorized(
                    typing.cast(
                        UnauthorizedResponse,
                        parse_obj_as(
                            type_=UnauthorizedResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 404:
                raise NotFound(
                    typing.cast(
                        NotFoundResponse,
                        parse_obj_as(
                            type_=NotFoundResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 405:
                raise MethodNotAllowed(
                    typing.cast(
                        MethodNotAllowedResponse,
                        parse_obj_as(
                            type_=MethodNotAllowedResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 429:
                raise RateLimitExceeded(
                    typing.cast(
                        RateLimitResponse,
                        parse_obj_as(
                            type_=RateLimitResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 500:
                raise InternalServerError(
                    typing.cast(
                        InternalServerErrorResponse,
                        parse_obj_as(
                            type_=InternalServerErrorResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    def get_project_entity_risk_summary(
        self,
        project_id: str,
        project_entity_id: str,
        *,
        filter: ProjectEntityRiskSummaryFilters,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> ProjectEntityRiskSummaryResponse:
        """
        Retrieves a risk summary for a specific project entity, including risk factors with network paths and risk intelligence data.

        **Response includes:**
        - Risk factors with their levels (elevated, high, critical)
        - Network paths showing relationships between entities
        - Risk intelligence scores and metadata
        - Risk categories and source entity information

        Parameters
        ----------
        project_id : str

        project_entity_id : str

        filter : ProjectEntityRiskSummaryFilters
            Filter risk factors by risk factor IDs and risk categories

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

        Returns
        -------
        ProjectEntityRiskSummaryResponse

        Examples
        --------
        from sayari import Sayari
        from sayari.project_entity import ProjectEntityRiskSummaryFilters

        client = Sayari(
            client_id="YOUR_CLIENT_ID",
            client_secret="YOUR_CLIENT_SECRET",
        )
        client.project_entity.get_project_entity_risk_summary(
            project_id="YVB88Y",
            project_entity_id="52z4Wa",
            filter=ProjectEntityRiskSummaryFilters(
                risk_factor=["sanctioned", "regulatory_action"],
                risk_category=["sanctions", "export_controls"],
            ),
        )
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v1/projects/{jsonable_encoder(project_id)}/entities/{jsonable_encoder(project_entity_id)}/risk_summary",
            method="GET",
            params={
                "filter": convert_and_respect_annotation_metadata(
                    object_=filter, annotation=ProjectEntityRiskSummaryFilters, direction="write"
                ),
            },
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                return typing.cast(
                    ProjectEntityRiskSummaryResponse,
                    parse_obj_as(
                        type_=ProjectEntityRiskSummaryResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
            if _response.status_code == 400:
                raise BadRequest(
                    typing.cast(
                        BadRequestResponse,
                        parse_obj_as(
                            type_=BadRequestResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 401:
                raise Unauthorized(
                    typing.cast(
                        UnauthorizedResponse,
                        parse_obj_as(
                            type_=UnauthorizedResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 404:
                raise NotFound(
                    typing.cast(
                        NotFoundResponse,
                        parse_obj_as(
                            type_=NotFoundResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 405:
                raise MethodNotAllowed(
                    typing.cast(
                        MethodNotAllowedResponse,
                        parse_obj_as(
                            type_=MethodNotAllowedResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 429:
                raise RateLimitExceeded(
                    typing.cast(
                        RateLimitResponse,
                        parse_obj_as(
                            type_=RateLimitResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 500:
                raise InternalServerError(
                    typing.cast(
                        InternalServerErrorResponse,
                        parse_obj_as(
                            type_=InternalServerErrorResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    def project_entity_supply_chain_summary(
        self,
        project_id: str,
        project_entity_id: str,
        *,
        product: typing.Optional[typing.Sequence[str]] = None,
        not_product: typing.Optional[typing.Sequence[str]] = None,
        risk_factors: typing.Optional[typing.Sequence[Risk]] = None,
        not_risk: typing.Optional[typing.Sequence[Risk]] = None,
        countries: typing.Optional[typing.Sequence[Country]] = None,
        not_countries: typing.Optional[typing.Sequence[Country]] = None,
        component: typing.Optional[typing.Sequence[str]] = None,
        not_component: typing.Optional[typing.Sequence[str]] = None,
        min_date: typing.Optional[str] = None,
        max_date: typing.Optional[str] = None,
        max_depth: typing.Optional[int] = None,
        limit: typing.Optional[int] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> ProjectEntitySupplyChainSummaryResponse:
        """
        Execute a traversal of the upstream trade network (supply chain) for all matched entities of a project entity, returning a summary of countries, risks, and components.

        Parameters
        ----------
        project_id : str
            The project Identifier

        project_entity_id : str
            The project entity Identifier

        product : typing.Optional[typing.Sequence[str]]
            Product root edge filter. Filters results to include only trade relationships where the associated component is part of the specified product's blueprint or is a sub-component of that product.

        not_product : typing.Optional[typing.Sequence[str]]
            Product root edge filter. Filters results to exclude any trade relationships where the associated component is part of the specified product's blueprint or is a sub-component of that product.

        risk_factors : typing.Optional[typing.Sequence[Risk]]
            Risk leaf node filter. Only return supply chains that end with a supplier that has 1+ of the specified risk factors.

        not_risk : typing.Optional[typing.Sequence[Risk]]
            Risk leaf node filter. Only return supply chains that end with a supplier that has none of the specified risk factors.

        countries : typing.Optional[typing.Sequence[Country]]
            Country leaf node filter. Only return supply chains that end with a supplier in 1+ of the specified countries.

        not_countries : typing.Optional[typing.Sequence[Country]]
            Country leaf node filter. Only return supply chains that end with a supplier in none of the specified countries.

        component : typing.Optional[typing.Sequence[str]]
            Component edge filter. Only return supply chains that contain at least one edge with 1+ of the specified HS codes.

        not_component : typing.Optional[typing.Sequence[str]]
            Component edge filter. Only return supply chains that contain no edges with any of the specified HS codes.

        min_date : typing.Optional[str]
            Minimum date edge filter in <YYYY-MM-DD> format. Only return supply chains with edge dates that are greater than or equal to this date.

        max_date : typing.Optional[str]
            Maximum date edge filter in <YYYY-MM-DD> format. Only return supply chains with edge dates that are less than or equal to this date.

        max_depth : typing.Optional[int]
            The maximum depth of the traversal, from 1 to 4 inclusive. Default is 4. Reduce if query is timing out.

        limit : typing.Optional[int]
            The maximum number of results to return. Default is no limit.

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

        Returns
        -------
        ProjectEntitySupplyChainSummaryResponse

        Examples
        --------
        from sayari import Sayari

        client = Sayari(
            client_id="YOUR_CLIENT_ID",
            client_secret="YOUR_CLIENT_SECRET",
        )
        client.project_entity.project_entity_supply_chain_summary(
            project_id="0n4473",
            project_entity_id="yebNPJ",
            max_depth=4,
        )
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v1/projects/{jsonable_encoder(project_id)}/entities/{jsonable_encoder(project_entity_id)}/supply_chain/upstream_summary",
            method="GET",
            params={
                "product": product,
                "-product": not_product,
                "risk_factors": risk_factors,
                "-risk_factors": not_risk,
                "countries": countries,
                "-countries": not_countries,
                "component": component,
                "-component": not_component,
                "min_date": min_date,
                "max_date": max_date,
                "max_depth": max_depth,
                "limit": limit,
            },
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                return typing.cast(
                    ProjectEntitySupplyChainSummaryResponse,
                    parse_obj_as(
                        type_=ProjectEntitySupplyChainSummaryResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
            if _response.status_code == 400:
                raise BadRequest(
                    typing.cast(
                        BadRequestResponse,
                        parse_obj_as(
                            type_=BadRequestResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 401:
                raise Unauthorized(
                    typing.cast(
                        UnauthorizedResponse,
                        parse_obj_as(
                            type_=UnauthorizedResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 404:
                raise NotFound(
                    typing.cast(
                        NotFoundResponse,
                        parse_obj_as(
                            type_=NotFoundResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 405:
                raise MethodNotAllowed(
                    typing.cast(
                        MethodNotAllowedResponse,
                        parse_obj_as(
                            type_=MethodNotAllowedResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 429:
                raise RateLimitExceeded(
                    typing.cast(
                        RateLimitResponse,
                        parse_obj_as(
                            type_=RateLimitResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 500:
                raise InternalServerError(
                    typing.cast(
                        InternalServerErrorResponse,
                        parse_obj_as(
                            type_=InternalServerErrorResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)


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

    async def create_project_entity(
        self,
        project_id: str,
        *,
        request: CreateResolvedProjectEntityRequest,
        enable_llm_clean: typing.Optional[bool] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> SingleProjectEntityResponse:
        """
        The resolution endpoints allow users to search for matching entities against a provided list of attributes. The endpoint is similar to the search endpoint, except it's tuned to only return the best match so the client doesn't need to do as much or any post-processing work to filter down results.

        Parameters
        ----------
        project_id : str

        request : CreateResolvedProjectEntityRequest

        enable_llm_clean : typing.Optional[bool]
            Whether to enable LLM-based data cleaning to remove noise and standardize entity attributes. Defaults to true if not supplied. Set to false to disable LLM cleaning.

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

        Returns
        -------
        SingleProjectEntityResponse

        Examples
        --------
        import asyncio

        from sayari import AsyncSayari
        from sayari.project_entity import CreateResolvedProjectEntityRequest

        client = AsyncSayari(
            client_id="YOUR_CLIENT_ID",
            client_secret="YOUR_CLIENT_SECRET",
        )


        async def main() -> None:
            await client.project_entity.create_project_entity(
                project_id="YVB88Y",
                request=CreateResolvedProjectEntityRequest(
                    name=["VTB Bank"],
                    country=["RUS"],
                    address=["Moscow"],
                    identifier=["253400V1H6ART1UQ0N98"],
                    profile="corporate",
                ),
            )


        asyncio.run(main())
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v1/projects/{jsonable_encoder(project_id)}/entities/create",
            method="POST",
            params={
                "enable_llm_clean": enable_llm_clean,
            },
            json=convert_and_respect_annotation_metadata(
                object_=request, annotation=CreateResolvedProjectEntityRequest, direction="write"
            ),
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                return typing.cast(
                    SingleProjectEntityResponse,
                    parse_obj_as(
                        type_=SingleProjectEntityResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
            if _response.status_code == 400:
                raise BadRequest(
                    typing.cast(
                        BadRequestResponse,
                        parse_obj_as(
                            type_=BadRequestResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 401:
                raise Unauthorized(
                    typing.cast(
                        UnauthorizedResponse,
                        parse_obj_as(
                            type_=UnauthorizedResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 404:
                raise NotFound(
                    typing.cast(
                        NotFoundResponse,
                        parse_obj_as(
                            type_=NotFoundResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 405:
                raise MethodNotAllowed(
                    typing.cast(
                        MethodNotAllowedResponse,
                        parse_obj_as(
                            type_=MethodNotAllowedResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 429:
                raise RateLimitExceeded(
                    typing.cast(
                        RateLimitResponse,
                        parse_obj_as(
                            type_=RateLimitResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 500:
                raise InternalServerError(
                    typing.cast(
                        InternalServerErrorResponse,
                        parse_obj_as(
                            type_=InternalServerErrorResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    async def get_project_entities(
        self,
        project_id: str,
        *,
        next: typing.Optional[str] = None,
        prev: typing.Optional[str] = None,
        limit: typing.Optional[int] = None,
        filter: typing.Optional[ProjectEntitiesFilter] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> ProjectEntitiesResponse:
        """
        Retrieves a list of entities for a specific project with pagination support.

        **Response Formats:**
        - **JSON** (default): Returns structured data with nested objects
        - **CSV**: Returns tabular data with dynamic columns for attributes and risk categories

        **CSV Format:**
        The CSV response includes dynamic columns based on the data:
        - `attribute_{field_name}`: Dynamic columns for each attribute field found in the data
        - `risk_category_{category_id}`: Dynamic columns for each risk category found in the data
        - Standard columns: project_id, project_entity_id, label, project_entity_url, upload_ids, strength, countries, tags, case_status, created_at, match_count, upstream_products, upstream_risk_factors, upstream_countries

        Use the `Accept: text/csv` header to request CSV format.

        Parameters
        ----------
        project_id : str

        next : typing.Optional[str]
            The pagination token for the next page of projects.

        prev : typing.Optional[str]
            The pagination token for the previous page of projects.

        limit : typing.Optional[int]
            Limit total values returned for projects. Defaults to 100. Max 100.

        filter : typing.Optional[ProjectEntitiesFilter]
            Filter the project entities. Supports both dot notation (e.g., 'filter.attribute.name') and bracket notation (e.g., 'filter[attribute][name]') for nested field filtering.

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

        Returns
        -------
        ProjectEntitiesResponse

        Examples
        --------
        import asyncio

        from sayari import AsyncSayari

        client = AsyncSayari(
            client_id="YOUR_CLIENT_ID",
            client_secret="YOUR_CLIENT_SECRET",
        )


        async def main() -> None:
            await client.project_entity.get_project_entities(
                project_id="YVB88Y",
            )


        asyncio.run(main())
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v1/projects/{jsonable_encoder(project_id)}/entities",
            method="GET",
            params={
                "next": next,
                "prev": prev,
                "limit": limit,
                "filter": convert_and_respect_annotation_metadata(
                    object_=filter, annotation=ProjectEntitiesFilter, direction="write"
                ),
            },
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                return typing.cast(
                    ProjectEntitiesResponse,
                    parse_obj_as(
                        type_=ProjectEntitiesResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
            if _response.status_code == 400:
                raise BadRequest(
                    typing.cast(
                        BadRequestResponse,
                        parse_obj_as(
                            type_=BadRequestResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 401:
                raise Unauthorized(
                    typing.cast(
                        UnauthorizedResponse,
                        parse_obj_as(
                            type_=UnauthorizedResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 404:
                raise NotFound(
                    typing.cast(
                        NotFoundResponse,
                        parse_obj_as(
                            type_=NotFoundResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 405:
                raise MethodNotAllowed(
                    typing.cast(
                        MethodNotAllowedResponse,
                        parse_obj_as(
                            type_=MethodNotAllowedResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 429:
                raise RateLimitExceeded(
                    typing.cast(
                        RateLimitResponse,
                        parse_obj_as(
                            type_=RateLimitResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 500:
                raise InternalServerError(
                    typing.cast(
                        InternalServerErrorResponse,
                        parse_obj_as(
                            type_=InternalServerErrorResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    async def get_project_entity(
        self, project_id: str, project_entity_id: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> SingleProjectEntityResponse:
        """
        Retrieves a specific entity in a project.

        Parameters
        ----------
        project_id : str

        project_entity_id : str

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

        Returns
        -------
        SingleProjectEntityResponse

        Examples
        --------
        import asyncio

        from sayari import AsyncSayari

        client = AsyncSayari(
            client_id="YOUR_CLIENT_ID",
            client_secret="YOUR_CLIENT_SECRET",
        )


        async def main() -> None:
            await client.project_entity.get_project_entity(
                project_id="project_id",
                project_entity_id="project_entity_id",
            )


        asyncio.run(main())
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v1/projects/{jsonable_encoder(project_id)}/entities/{jsonable_encoder(project_entity_id)}",
            method="GET",
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                return typing.cast(
                    SingleProjectEntityResponse,
                    parse_obj_as(
                        type_=SingleProjectEntityResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
            if _response.status_code == 400:
                raise BadRequest(
                    typing.cast(
                        BadRequestResponse,
                        parse_obj_as(
                            type_=BadRequestResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 401:
                raise Unauthorized(
                    typing.cast(
                        UnauthorizedResponse,
                        parse_obj_as(
                            type_=UnauthorizedResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 404:
                raise NotFound(
                    typing.cast(
                        NotFoundResponse,
                        parse_obj_as(
                            type_=NotFoundResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 405:
                raise MethodNotAllowed(
                    typing.cast(
                        MethodNotAllowedResponse,
                        parse_obj_as(
                            type_=MethodNotAllowedResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 429:
                raise RateLimitExceeded(
                    typing.cast(
                        RateLimitResponse,
                        parse_obj_as(
                            type_=RateLimitResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 500:
                raise InternalServerError(
                    typing.cast(
                        InternalServerErrorResponse,
                        parse_obj_as(
                            type_=InternalServerErrorResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    async def delete_project_entity(
        self, project_id: str, project_entity_id: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> None:
        """
        Deletes a project entity.

        Parameters
        ----------
        project_id : str

        project_entity_id : str

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

        Returns
        -------
        None

        Examples
        --------
        import asyncio

        from sayari import AsyncSayari

        client = AsyncSayari(
            client_id="YOUR_CLIENT_ID",
            client_secret="YOUR_CLIENT_SECRET",
        )


        async def main() -> None:
            await client.project_entity.delete_project_entity(
                project_id="project_id",
                project_entity_id="project_entity_id",
            )


        asyncio.run(main())
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v1/projects/{jsonable_encoder(project_id)}/entities/{jsonable_encoder(project_entity_id)}",
            method="DELETE",
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                return
            if _response.status_code == 400:
                raise BadRequest(
                    typing.cast(
                        BadRequestResponse,
                        parse_obj_as(
                            type_=BadRequestResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 401:
                raise Unauthorized(
                    typing.cast(
                        UnauthorizedResponse,
                        parse_obj_as(
                            type_=UnauthorizedResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 404:
                raise NotFound(
                    typing.cast(
                        NotFoundResponse,
                        parse_obj_as(
                            type_=NotFoundResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 405:
                raise MethodNotAllowed(
                    typing.cast(
                        MethodNotAllowedResponse,
                        parse_obj_as(
                            type_=MethodNotAllowedResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 429:
                raise RateLimitExceeded(
                    typing.cast(
                        RateLimitResponse,
                        parse_obj_as(
                            type_=RateLimitResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 500:
                raise InternalServerError(
                    typing.cast(
                        InternalServerErrorResponse,
                        parse_obj_as(
                            type_=InternalServerErrorResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    async def delete_project_entity_match(
        self,
        project_id: str,
        project_entity_id: str,
        match_id: str,
        *,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> None:
        """
        Deletes a specific project entity match.

        Parameters
        ----------
        project_id : str

        project_entity_id : str

        match_id : str

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

        Returns
        -------
        None

        Examples
        --------
        import asyncio

        from sayari import AsyncSayari

        client = AsyncSayari(
            client_id="YOUR_CLIENT_ID",
            client_secret="YOUR_CLIENT_SECRET",
        )


        async def main() -> None:
            await client.project_entity.delete_project_entity_match(
                project_id="project_id",
                project_entity_id="project_entity_id",
                match_id="match_id",
            )


        asyncio.run(main())
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v1/projects/{jsonable_encoder(project_id)}/entities/{jsonable_encoder(project_entity_id)}/matches/{jsonable_encoder(match_id)}",
            method="DELETE",
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                return
            if _response.status_code == 400:
                raise BadRequest(
                    typing.cast(
                        BadRequestResponse,
                        parse_obj_as(
                            type_=BadRequestResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 401:
                raise Unauthorized(
                    typing.cast(
                        UnauthorizedResponse,
                        parse_obj_as(
                            type_=UnauthorizedResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 404:
                raise NotFound(
                    typing.cast(
                        NotFoundResponse,
                        parse_obj_as(
                            type_=NotFoundResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 405:
                raise MethodNotAllowed(
                    typing.cast(
                        MethodNotAllowedResponse,
                        parse_obj_as(
                            type_=MethodNotAllowedResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 429:
                raise RateLimitExceeded(
                    typing.cast(
                        RateLimitResponse,
                        parse_obj_as(
                            type_=RateLimitResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 500:
                raise InternalServerError(
                    typing.cast(
                        InternalServerErrorResponse,
                        parse_obj_as(
                            type_=InternalServerErrorResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    async def project_entity_exists(
        self, project_id: str, *, request: ResolutionAttributes, request_options: typing.Optional[RequestOptions] = None
    ) -> ProjectEntityIdResponse:
        """
        Checks if a project entity with the given attributes already exists.

        Parameters
        ----------
        project_id : str

        request : ResolutionAttributes

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

        Returns
        -------
        ProjectEntityIdResponse

        Examples
        --------
        import asyncio

        from sayari import AsyncSayari
        from sayari.project_entity import ResolutionAttributes

        client = AsyncSayari(
            client_id="YOUR_CLIENT_ID",
            client_secret="YOUR_CLIENT_SECRET",
        )


        async def main() -> None:
            await client.project_entity.project_entity_exists(
                project_id="YVB88Y",
                request=ResolutionAttributes(
                    name=["Example Company"],
                    country=["USA"],
                ),
            )


        asyncio.run(main())
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v1/projects/{jsonable_encoder(project_id)}/entities/exists",
            method="POST",
            json=convert_and_respect_annotation_metadata(
                object_=request, annotation=ResolutionAttributes, direction="write"
            ),
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                return typing.cast(
                    ProjectEntityIdResponse,
                    parse_obj_as(
                        type_=ProjectEntityIdResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
            if _response.status_code == 400:
                raise BadRequest(
                    typing.cast(
                        BadRequestResponse,
                        parse_obj_as(
                            type_=BadRequestResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 401:
                raise Unauthorized(
                    typing.cast(
                        UnauthorizedResponse,
                        parse_obj_as(
                            type_=UnauthorizedResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 404:
                raise NotFound(
                    typing.cast(
                        NotFoundResponse,
                        parse_obj_as(
                            type_=NotFoundResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 405:
                raise MethodNotAllowed(
                    typing.cast(
                        MethodNotAllowedResponse,
                        parse_obj_as(
                            type_=MethodNotAllowedResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 429:
                raise RateLimitExceeded(
                    typing.cast(
                        RateLimitResponse,
                        parse_obj_as(
                            type_=RateLimitResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 500:
                raise InternalServerError(
                    typing.cast(
                        InternalServerErrorResponse,
                        parse_obj_as(
                            type_=InternalServerErrorResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    async def save_project_entity(
        self,
        project_id: str,
        *,
        request: SaveProjectEntityBody,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> ProjectEntityIdResponse:
        """
        Stores a project entity given entity IDs and a list of attributes.

        Parameters
        ----------
        project_id : str

        request : SaveProjectEntityBody

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

        Returns
        -------
        ProjectEntityIdResponse

        Examples
        --------
        import asyncio

        from sayari import AsyncSayari
        from sayari.project_entity import ResolutionAttributes, SaveProjectEntityBody

        client = AsyncSayari(
            client_id="YOUR_CLIENT_ID",
            client_secret="YOUR_CLIENT_SECRET",
        )


        async def main() -> None:
            await client.project_entity.save_project_entity(
                project_id="YVB88Y",
                request=SaveProjectEntityBody(
                    entity_ids=["entity_id_1", "entity_id_2"],
                    attributes=ResolutionAttributes(
                        name=["Example Company"],
                        country=["USA"],
                    ),
                    profile="corporate",
                ),
            )


        asyncio.run(main())
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v1/projects/{jsonable_encoder(project_id)}/entities/save",
            method="POST",
            json=convert_and_respect_annotation_metadata(
                object_=request, annotation=SaveProjectEntityBody, direction="write"
            ),
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                return typing.cast(
                    ProjectEntityIdResponse,
                    parse_obj_as(
                        type_=ProjectEntityIdResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
            if _response.status_code == 400:
                raise BadRequest(
                    typing.cast(
                        BadRequestResponse,
                        parse_obj_as(
                            type_=BadRequestResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 401:
                raise Unauthorized(
                    typing.cast(
                        UnauthorizedResponse,
                        parse_obj_as(
                            type_=UnauthorizedResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 404:
                raise NotFound(
                    typing.cast(
                        NotFoundResponse,
                        parse_obj_as(
                            type_=NotFoundResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 405:
                raise MethodNotAllowed(
                    typing.cast(
                        MethodNotAllowedResponse,
                        parse_obj_as(
                            type_=MethodNotAllowedResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 429:
                raise RateLimitExceeded(
                    typing.cast(
                        RateLimitResponse,
                        parse_obj_as(
                            type_=RateLimitResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 500:
                raise InternalServerError(
                    typing.cast(
                        InternalServerErrorResponse,
                        parse_obj_as(
                            type_=InternalServerErrorResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    async def get_project_risk_changes(
        self,
        project_id: str,
        *,
        limit: typing.Optional[int] = None,
        next: typing.Optional[str] = None,
        prev: typing.Optional[str] = None,
        sort_date: typing.Optional[SortOrder] = None,
        filter_from: typing.Optional[str] = None,
        filter_to: typing.Optional[str] = None,
        filter_risk_factor: typing.Optional[typing.Sequence[str]] = None,
        filter_risk_category: typing.Optional[typing.Sequence[str]] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> ProjectRiskChangesResponse:
        """
        Retrieves the risk changes for all project entities in a project.

        Parameters
        ----------
        project_id : str

        limit : typing.Optional[int]
            The maximum number of risk changes to return. Default is 100.

        next : typing.Optional[str]
            Token to retrieve the next page of risk changes

        prev : typing.Optional[str]
            Token to retrieve the previous page of risk changes

        sort_date : typing.Optional[SortOrder]
            Sort by timestamp in ascending or descending order. Default is desc.

        filter_from : typing.Optional[str]
            Filter risk changes from the provided date

        filter_to : typing.Optional[str]
            Filter risk changes up to the provided date

        filter_risk_factor : typing.Optional[typing.Sequence[str]]
            Filter risk changes for the provided risk factors

        filter_risk_category : typing.Optional[typing.Sequence[str]]
            Filter risk changes for risk factors from the provided risk categories

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

        Returns
        -------
        ProjectRiskChangesResponse

        Examples
        --------
        import asyncio

        from sayari import AsyncSayari

        client = AsyncSayari(
            client_id="YOUR_CLIENT_ID",
            client_secret="YOUR_CLIENT_SECRET",
        )


        async def main() -> None:
            await client.project_entity.get_project_risk_changes(
                project_id="YVB88Y",
            )


        asyncio.run(main())
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v1/projects/{jsonable_encoder(project_id)}/entities/changes/risk",
            method="GET",
            params={
                "limit": limit,
                "next": next,
                "prev": prev,
                "sort.date": sort_date,
                "filter.from": filter_from,
                "filter.to": filter_to,
                "filter.risk_factor": filter_risk_factor,
                "filter.risk_category": filter_risk_category,
            },
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                return typing.cast(
                    ProjectRiskChangesResponse,
                    parse_obj_as(
                        type_=ProjectRiskChangesResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
            if _response.status_code == 400:
                raise BadRequest(
                    typing.cast(
                        BadRequestResponse,
                        parse_obj_as(
                            type_=BadRequestResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 401:
                raise Unauthorized(
                    typing.cast(
                        UnauthorizedResponse,
                        parse_obj_as(
                            type_=UnauthorizedResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 404:
                raise NotFound(
                    typing.cast(
                        NotFoundResponse,
                        parse_obj_as(
                            type_=NotFoundResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 405:
                raise MethodNotAllowed(
                    typing.cast(
                        MethodNotAllowedResponse,
                        parse_obj_as(
                            type_=MethodNotAllowedResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 422:
                raise UnprocessableContent(
                    typing.cast(
                        UnprocessableContentResponse,
                        parse_obj_as(
                            type_=UnprocessableContentResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 429:
                raise RateLimitExceeded(
                    typing.cast(
                        RateLimitResponse,
                        parse_obj_as(
                            type_=RateLimitResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 500:
                raise InternalServerError(
                    typing.cast(
                        InternalServerErrorResponse,
                        parse_obj_as(
                            type_=InternalServerErrorResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    async def get_project_entity_risk_changes(
        self,
        project_id: str,
        project_entity_id: str,
        *,
        limit: typing.Optional[int] = None,
        next: typing.Optional[str] = None,
        prev: typing.Optional[str] = None,
        sort_date: typing.Optional[SortOrder] = None,
        filter_from: typing.Optional[str] = None,
        filter_to: typing.Optional[str] = None,
        filter_risk_factor: typing.Optional[typing.Sequence[str]] = None,
        filter_risk_category: typing.Optional[typing.Sequence[str]] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> ProjectEntityRiskChangesResponse:
        """
        Retrieves the risk changes for a single project entity.

        Parameters
        ----------
        project_id : str

        project_entity_id : str

        limit : typing.Optional[int]
            The maximum number of risk changes to return. Default is 100.

        next : typing.Optional[str]
            Token to retrieve the next page of risk changes

        prev : typing.Optional[str]
            Token to retrieve the previous page of risk changes

        sort_date : typing.Optional[SortOrder]
            Sort by timestamp in ascending or descending order. Default is desc.

        filter_from : typing.Optional[str]
            Filter risk changes from the provided date

        filter_to : typing.Optional[str]
            Filter risk changes up to the provided date

        filter_risk_factor : typing.Optional[typing.Sequence[str]]
            Filter risk changes for the provided risk factors

        filter_risk_category : typing.Optional[typing.Sequence[str]]
            Filter risk changes for risk factors from the provided risk categories

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

        Returns
        -------
        ProjectEntityRiskChangesResponse

        Examples
        --------
        import asyncio

        from sayari import AsyncSayari

        client = AsyncSayari(
            client_id="YOUR_CLIENT_ID",
            client_secret="YOUR_CLIENT_SECRET",
        )


        async def main() -> None:
            await client.project_entity.get_project_entity_risk_changes(
                project_id="YVB88Y",
                project_entity_id="52z4Wa",
            )


        asyncio.run(main())
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v1/projects/{jsonable_encoder(project_id)}/entities/{jsonable_encoder(project_entity_id)}/changes/risk",
            method="GET",
            params={
                "limit": limit,
                "next": next,
                "prev": prev,
                "sort.date": sort_date,
                "filter.from": filter_from,
                "filter.to": filter_to,
                "filter.risk_factor": filter_risk_factor,
                "filter.risk_category": filter_risk_category,
            },
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                return typing.cast(
                    ProjectEntityRiskChangesResponse,
                    parse_obj_as(
                        type_=ProjectEntityRiskChangesResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
            if _response.status_code == 400:
                raise BadRequest(
                    typing.cast(
                        BadRequestResponse,
                        parse_obj_as(
                            type_=BadRequestResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 401:
                raise Unauthorized(
                    typing.cast(
                        UnauthorizedResponse,
                        parse_obj_as(
                            type_=UnauthorizedResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 404:
                raise NotFound(
                    typing.cast(
                        NotFoundResponse,
                        parse_obj_as(
                            type_=NotFoundResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 405:
                raise MethodNotAllowed(
                    typing.cast(
                        MethodNotAllowedResponse,
                        parse_obj_as(
                            type_=MethodNotAllowedResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 422:
                raise UnprocessableContent(
                    typing.cast(
                        UnprocessableContentResponse,
                        parse_obj_as(
                            type_=UnprocessableContentResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 429:
                raise RateLimitExceeded(
                    typing.cast(
                        RateLimitResponse,
                        parse_obj_as(
                            type_=RateLimitResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 500:
                raise InternalServerError(
                    typing.cast(
                        InternalServerErrorResponse,
                        parse_obj_as(
                            type_=InternalServerErrorResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    async def delete_project_risk_changes(
        self, project_id: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> None:
        """
        Dismiss risk changes for all project entities in a project.

        Parameters
        ----------
        project_id : str

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

        Returns
        -------
        None

        Examples
        --------
        import asyncio

        from sayari import AsyncSayari

        client = AsyncSayari(
            client_id="YOUR_CLIENT_ID",
            client_secret="YOUR_CLIENT_SECRET",
        )


        async def main() -> None:
            await client.project_entity.delete_project_risk_changes(
                project_id="project_id",
            )


        asyncio.run(main())
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v1/projects/{jsonable_encoder(project_id)}/entities/changes/risk",
            method="DELETE",
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                return
            if _response.status_code == 400:
                raise BadRequest(
                    typing.cast(
                        BadRequestResponse,
                        parse_obj_as(
                            type_=BadRequestResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 401:
                raise Unauthorized(
                    typing.cast(
                        UnauthorizedResponse,
                        parse_obj_as(
                            type_=UnauthorizedResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 404:
                raise NotFound(
                    typing.cast(
                        NotFoundResponse,
                        parse_obj_as(
                            type_=NotFoundResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 405:
                raise MethodNotAllowed(
                    typing.cast(
                        MethodNotAllowedResponse,
                        parse_obj_as(
                            type_=MethodNotAllowedResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 429:
                raise RateLimitExceeded(
                    typing.cast(
                        RateLimitResponse,
                        parse_obj_as(
                            type_=RateLimitResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 500:
                raise InternalServerError(
                    typing.cast(
                        InternalServerErrorResponse,
                        parse_obj_as(
                            type_=InternalServerErrorResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    async def delete_project_entity_risk_changes(
        self, project_id: str, project_entity_id: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> None:
        """
        Dismiss risk changes for a single project entity.

        Parameters
        ----------
        project_id : str

        project_entity_id : str

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

        Returns
        -------
        None

        Examples
        --------
        import asyncio

        from sayari import AsyncSayari

        client = AsyncSayari(
            client_id="YOUR_CLIENT_ID",
            client_secret="YOUR_CLIENT_SECRET",
        )


        async def main() -> None:
            await client.project_entity.delete_project_entity_risk_changes(
                project_id="project_id",
                project_entity_id="project_entity_id",
            )


        asyncio.run(main())
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v1/projects/{jsonable_encoder(project_id)}/entities/{jsonable_encoder(project_entity_id)}/changes/risk",
            method="DELETE",
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                return
            if _response.status_code == 400:
                raise BadRequest(
                    typing.cast(
                        BadRequestResponse,
                        parse_obj_as(
                            type_=BadRequestResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 401:
                raise Unauthorized(
                    typing.cast(
                        UnauthorizedResponse,
                        parse_obj_as(
                            type_=UnauthorizedResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 404:
                raise NotFound(
                    typing.cast(
                        NotFoundResponse,
                        parse_obj_as(
                            type_=NotFoundResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 405:
                raise MethodNotAllowed(
                    typing.cast(
                        MethodNotAllowedResponse,
                        parse_obj_as(
                            type_=MethodNotAllowedResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 429:
                raise RateLimitExceeded(
                    typing.cast(
                        RateLimitResponse,
                        parse_obj_as(
                            type_=RateLimitResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 500:
                raise InternalServerError(
                    typing.cast(
                        InternalServerErrorResponse,
                        parse_obj_as(
                            type_=InternalServerErrorResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    async def project_entity_supply_chain(
        self,
        project_id: str,
        project_entity_id: str,
        *,
        product: typing.Optional[typing.Sequence[str]] = None,
        not_product: typing.Optional[typing.Sequence[str]] = None,
        risk: typing.Optional[typing.Sequence[Risk]] = None,
        not_risk: typing.Optional[typing.Sequence[Risk]] = None,
        countries: typing.Optional[typing.Sequence[Country]] = None,
        not_countries: typing.Optional[typing.Sequence[Country]] = None,
        shipment_country: typing.Optional[typing.Sequence[Country]] = None,
        not_shipment_country: typing.Optional[typing.Sequence[Country]] = None,
        tier_1_shipment_country: typing.Optional[typing.Sequence[Country]] = None,
        tier_2_shipment_country: typing.Optional[typing.Sequence[Country]] = None,
        tier_3_shipment_country: typing.Optional[typing.Sequence[Country]] = None,
        tier_4_shipment_country: typing.Optional[typing.Sequence[Country]] = None,
        tier_5_shipment_country: typing.Optional[typing.Sequence[Country]] = None,
        component: typing.Optional[typing.Sequence[str]] = None,
        not_component: typing.Optional[typing.Sequence[str]] = None,
        min_date: typing.Optional[str] = None,
        max_date: typing.Optional[str] = None,
        max_depth: typing.Optional[int] = None,
        limit: typing.Optional[int] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> UpstreamTradeTraversalResponse:
        """
        Execute a traversal of the upstream trade network (supply chain) for all matched entities of a project entity, returning a set of entities and edges between them.

        Parameters
        ----------
        project_id : str
            The project Identifier

        project_entity_id : str
            The project entity Identifier

        product : typing.Optional[typing.Sequence[str]]
            Product root edge filter. Filters results to include only trade relationships where the associated component is part of the specified product's blueprint or is a sub-component of that product.

        not_product : typing.Optional[typing.Sequence[str]]
            Product root edge filter. Filters results to exclude any trade relationships where the associated component is part of the specified product's blueprint or is a sub-component of that product.

        risk : typing.Optional[typing.Sequence[Risk]]
            Risk leaf node filter. Only return supply chains that end with a supplier that has 1+ of the specified risk factors.

        not_risk : typing.Optional[typing.Sequence[Risk]]
            Risk leaf node filter. Only return supply chains that end with a supplier that has none of the specified risk factors.

        countries : typing.Optional[typing.Sequence[Country]]
            Country leaf node filter. Only return supply chains that end with a supplier in 1+ of the specified countries.

        not_countries : typing.Optional[typing.Sequence[Country]]
            Country leaf node filter. Only return supply chains that end with a supplier in none of the specified countries.

        shipment_country : typing.Optional[typing.Sequence[Country]]
            Filters supply chain paths where 1+ shipment country from any tier matches the provided values.

        not_shipment_country : typing.Optional[typing.Sequence[Country]]
            Filters supply chain paths where none of the shipment countries from any tier matches the provided values.

        tier_1_shipment_country : typing.Optional[typing.Sequence[Country]]
            Filters supply chain paths where 1+ shipment country from tier 1 matches the provided values.

        tier_2_shipment_country : typing.Optional[typing.Sequence[Country]]
            Filters supply chain paths where 1+ shipment country from tier 2 matches the provided values.

        tier_3_shipment_country : typing.Optional[typing.Sequence[Country]]
            Filters supply chain paths where 1+ shipment country from tier 3 matches the provided values.

        tier_4_shipment_country : typing.Optional[typing.Sequence[Country]]
            Filters supply chain paths where 1+ shipment country from tier 4 matches the provided values.

        tier_5_shipment_country : typing.Optional[typing.Sequence[Country]]
            Filters supply chain paths where 1+ shipment country from tier 5 matches the provided values.

        component : typing.Optional[typing.Sequence[str]]
            Component edge filter. Only return supply chains that contain at least one edge with 1+ of the specified HS codes.

        not_component : typing.Optional[typing.Sequence[str]]
            Component edge filter. Only return supply chains that contain no edges with any of the specified HS codes.

        min_date : typing.Optional[str]
            Minimum date edge filter in <YYYY-MM-DD> format. Only return supply chains with edge dates that are greater than or equal to this date.

        max_date : typing.Optional[str]
            Maximum date edge filter in <YYYY-MM-DD> format. Only return supply chains with edge dates that are less than or equal to this date.

        max_depth : typing.Optional[int]
            The maximum depth of the traversal, from 1 to 4 inclusive. Default is 4. Reduce if query is timing out.

        limit : typing.Optional[int]
            The maximum number of results to return. Default is no limit.

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

        Returns
        -------
        UpstreamTradeTraversalResponse

        Examples
        --------
        import asyncio

        from sayari import AsyncSayari

        client = AsyncSayari(
            client_id="YOUR_CLIENT_ID",
            client_secret="YOUR_CLIENT_SECRET",
        )


        async def main() -> None:
            await client.project_entity.project_entity_supply_chain(
                project_id="0n4473",
                project_entity_id="yebNPJ",
                product=["6004"],
                limit=1,
            )


        asyncio.run(main())
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v1/projects/{jsonable_encoder(project_id)}/entities/{jsonable_encoder(project_entity_id)}/supply_chain/upstream",
            method="GET",
            params={
                "product": product,
                "-product": not_product,
                "risk": risk,
                "-risk": not_risk,
                "countries": countries,
                "-countries": not_countries,
                "shipment_country": shipment_country,
                "-shipment_country": not_shipment_country,
                "tier1_shipment_country": tier_1_shipment_country,
                "tier2_shipment_country": tier_2_shipment_country,
                "tier3_shipment_country": tier_3_shipment_country,
                "tier4_shipment_country": tier_4_shipment_country,
                "tier5_shipment_country": tier_5_shipment_country,
                "component": component,
                "-component": not_component,
                "min_date": min_date,
                "max_date": max_date,
                "max_depth": max_depth,
                "limit": limit,
            },
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                return typing.cast(
                    UpstreamTradeTraversalResponse,
                    parse_obj_as(
                        type_=UpstreamTradeTraversalResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
            if _response.status_code == 400:
                raise BadRequest(
                    typing.cast(
                        BadRequestResponse,
                        parse_obj_as(
                            type_=BadRequestResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 401:
                raise Unauthorized(
                    typing.cast(
                        UnauthorizedResponse,
                        parse_obj_as(
                            type_=UnauthorizedResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 404:
                raise NotFound(
                    typing.cast(
                        NotFoundResponse,
                        parse_obj_as(
                            type_=NotFoundResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 405:
                raise MethodNotAllowed(
                    typing.cast(
                        MethodNotAllowedResponse,
                        parse_obj_as(
                            type_=MethodNotAllowedResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 429:
                raise RateLimitExceeded(
                    typing.cast(
                        RateLimitResponse,
                        parse_obj_as(
                            type_=RateLimitResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 500:
                raise InternalServerError(
                    typing.cast(
                        InternalServerErrorResponse,
                        parse_obj_as(
                            type_=InternalServerErrorResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    async def get_project_entity_risk_summary(
        self,
        project_id: str,
        project_entity_id: str,
        *,
        filter: ProjectEntityRiskSummaryFilters,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> ProjectEntityRiskSummaryResponse:
        """
        Retrieves a risk summary for a specific project entity, including risk factors with network paths and risk intelligence data.

        **Response includes:**
        - Risk factors with their levels (elevated, high, critical)
        - Network paths showing relationships between entities
        - Risk intelligence scores and metadata
        - Risk categories and source entity information

        Parameters
        ----------
        project_id : str

        project_entity_id : str

        filter : ProjectEntityRiskSummaryFilters
            Filter risk factors by risk factor IDs and risk categories

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

        Returns
        -------
        ProjectEntityRiskSummaryResponse

        Examples
        --------
        import asyncio

        from sayari import AsyncSayari
        from sayari.project_entity import ProjectEntityRiskSummaryFilters

        client = AsyncSayari(
            client_id="YOUR_CLIENT_ID",
            client_secret="YOUR_CLIENT_SECRET",
        )


        async def main() -> None:
            await client.project_entity.get_project_entity_risk_summary(
                project_id="YVB88Y",
                project_entity_id="52z4Wa",
                filter=ProjectEntityRiskSummaryFilters(
                    risk_factor=["sanctioned", "regulatory_action"],
                    risk_category=["sanctions", "export_controls"],
                ),
            )


        asyncio.run(main())
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v1/projects/{jsonable_encoder(project_id)}/entities/{jsonable_encoder(project_entity_id)}/risk_summary",
            method="GET",
            params={
                "filter": convert_and_respect_annotation_metadata(
                    object_=filter, annotation=ProjectEntityRiskSummaryFilters, direction="write"
                ),
            },
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                return typing.cast(
                    ProjectEntityRiskSummaryResponse,
                    parse_obj_as(
                        type_=ProjectEntityRiskSummaryResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
            if _response.status_code == 400:
                raise BadRequest(
                    typing.cast(
                        BadRequestResponse,
                        parse_obj_as(
                            type_=BadRequestResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 401:
                raise Unauthorized(
                    typing.cast(
                        UnauthorizedResponse,
                        parse_obj_as(
                            type_=UnauthorizedResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 404:
                raise NotFound(
                    typing.cast(
                        NotFoundResponse,
                        parse_obj_as(
                            type_=NotFoundResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 405:
                raise MethodNotAllowed(
                    typing.cast(
                        MethodNotAllowedResponse,
                        parse_obj_as(
                            type_=MethodNotAllowedResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 429:
                raise RateLimitExceeded(
                    typing.cast(
                        RateLimitResponse,
                        parse_obj_as(
                            type_=RateLimitResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 500:
                raise InternalServerError(
                    typing.cast(
                        InternalServerErrorResponse,
                        parse_obj_as(
                            type_=InternalServerErrorResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    async def project_entity_supply_chain_summary(
        self,
        project_id: str,
        project_entity_id: str,
        *,
        product: typing.Optional[typing.Sequence[str]] = None,
        not_product: typing.Optional[typing.Sequence[str]] = None,
        risk_factors: typing.Optional[typing.Sequence[Risk]] = None,
        not_risk: typing.Optional[typing.Sequence[Risk]] = None,
        countries: typing.Optional[typing.Sequence[Country]] = None,
        not_countries: typing.Optional[typing.Sequence[Country]] = None,
        component: typing.Optional[typing.Sequence[str]] = None,
        not_component: typing.Optional[typing.Sequence[str]] = None,
        min_date: typing.Optional[str] = None,
        max_date: typing.Optional[str] = None,
        max_depth: typing.Optional[int] = None,
        limit: typing.Optional[int] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> ProjectEntitySupplyChainSummaryResponse:
        """
        Execute a traversal of the upstream trade network (supply chain) for all matched entities of a project entity, returning a summary of countries, risks, and components.

        Parameters
        ----------
        project_id : str
            The project Identifier

        project_entity_id : str
            The project entity Identifier

        product : typing.Optional[typing.Sequence[str]]
            Product root edge filter. Filters results to include only trade relationships where the associated component is part of the specified product's blueprint or is a sub-component of that product.

        not_product : typing.Optional[typing.Sequence[str]]
            Product root edge filter. Filters results to exclude any trade relationships where the associated component is part of the specified product's blueprint or is a sub-component of that product.

        risk_factors : typing.Optional[typing.Sequence[Risk]]
            Risk leaf node filter. Only return supply chains that end with a supplier that has 1+ of the specified risk factors.

        not_risk : typing.Optional[typing.Sequence[Risk]]
            Risk leaf node filter. Only return supply chains that end with a supplier that has none of the specified risk factors.

        countries : typing.Optional[typing.Sequence[Country]]
            Country leaf node filter. Only return supply chains that end with a supplier in 1+ of the specified countries.

        not_countries : typing.Optional[typing.Sequence[Country]]
            Country leaf node filter. Only return supply chains that end with a supplier in none of the specified countries.

        component : typing.Optional[typing.Sequence[str]]
            Component edge filter. Only return supply chains that contain at least one edge with 1+ of the specified HS codes.

        not_component : typing.Optional[typing.Sequence[str]]
            Component edge filter. Only return supply chains that contain no edges with any of the specified HS codes.

        min_date : typing.Optional[str]
            Minimum date edge filter in <YYYY-MM-DD> format. Only return supply chains with edge dates that are greater than or equal to this date.

        max_date : typing.Optional[str]
            Maximum date edge filter in <YYYY-MM-DD> format. Only return supply chains with edge dates that are less than or equal to this date.

        max_depth : typing.Optional[int]
            The maximum depth of the traversal, from 1 to 4 inclusive. Default is 4. Reduce if query is timing out.

        limit : typing.Optional[int]
            The maximum number of results to return. Default is no limit.

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

        Returns
        -------
        ProjectEntitySupplyChainSummaryResponse

        Examples
        --------
        import asyncio

        from sayari import AsyncSayari

        client = AsyncSayari(
            client_id="YOUR_CLIENT_ID",
            client_secret="YOUR_CLIENT_SECRET",
        )


        async def main() -> None:
            await client.project_entity.project_entity_supply_chain_summary(
                project_id="0n4473",
                project_entity_id="yebNPJ",
                max_depth=4,
            )


        asyncio.run(main())
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v1/projects/{jsonable_encoder(project_id)}/entities/{jsonable_encoder(project_entity_id)}/supply_chain/upstream_summary",
            method="GET",
            params={
                "product": product,
                "-product": not_product,
                "risk_factors": risk_factors,
                "-risk_factors": not_risk,
                "countries": countries,
                "-countries": not_countries,
                "component": component,
                "-component": not_component,
                "min_date": min_date,
                "max_date": max_date,
                "max_depth": max_depth,
                "limit": limit,
            },
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                return typing.cast(
                    ProjectEntitySupplyChainSummaryResponse,
                    parse_obj_as(
                        type_=ProjectEntitySupplyChainSummaryResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
            if _response.status_code == 400:
                raise BadRequest(
                    typing.cast(
                        BadRequestResponse,
                        parse_obj_as(
                            type_=BadRequestResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 401:
                raise Unauthorized(
                    typing.cast(
                        UnauthorizedResponse,
                        parse_obj_as(
                            type_=UnauthorizedResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 404:
                raise NotFound(
                    typing.cast(
                        NotFoundResponse,
                        parse_obj_as(
                            type_=NotFoundResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 405:
                raise MethodNotAllowed(
                    typing.cast(
                        MethodNotAllowedResponse,
                        parse_obj_as(
                            type_=MethodNotAllowedResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 429:
                raise RateLimitExceeded(
                    typing.cast(
                        RateLimitResponse,
                        parse_obj_as(
                            type_=RateLimitResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 500:
                raise InternalServerError(
                    typing.cast(
                        InternalServerErrorResponse,
                        parse_obj_as(
                            type_=InternalServerErrorResponse,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)
