# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.

from __future__ import annotations

import httpx

from ..types import contact_list_params, contact_create_params, contact_update_params
from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
from .._utils import path_template, maybe_transform, async_maybe_transform
from .._compat import cached_property
from .._resource import SyncAPIResource, AsyncAPIResource
from .._response import (
    to_raw_response_wrapper,
    to_streamed_response_wrapper,
    async_to_raw_response_wrapper,
    async_to_streamed_response_wrapper,
)
from .._base_client import make_request_options
from ..types.contact_list_response import ContactListResponse
from ..types.contact_create_response import ContactCreateResponse
from ..types.contact_update_response import ContactUpdateResponse
from ..types.contact_retrieve_response import ContactRetrieveResponse
from ..types.contact_definitions_response import ContactDefinitionsResponse

__all__ = ["ContactResource", "AsyncContactResource"]


class ContactResource(SyncAPIResource):
    """Contacts represent individual people in Lightfield.

    Contacts can be associated with one or more accounts.
    """

    @cached_property
    def with_raw_response(self) -> ContactResourceWithRawResponse:
        """
        This property can be used as a prefix for any HTTP method call to return
        the raw response object instead of the parsed content.

        For more information, see https://www.github.com/Lightfld/lightfield-python#accessing-raw-response-data-eg-headers
        """
        return ContactResourceWithRawResponse(self)

    @cached_property
    def with_streaming_response(self) -> ContactResourceWithStreamingResponse:
        """
        An alternative to `.with_raw_response` that doesn't eagerly read the response body.

        For more information, see https://www.github.com/Lightfld/lightfield-python#with_streaming_response
        """
        return ContactResourceWithStreamingResponse(self)

    def create(
        self,
        *,
        fields: contact_create_params.Fields,
        relationships: contact_create_params.Relationships | Omit = omit,
        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
        # The extra values given here take precedence over values defined on the client or passed to this method.
        extra_headers: Headers | None = None,
        extra_query: Query | None = None,
        extra_body: Body | None = None,
        timeout: float | httpx.Timeout | None | NotGiven = not_given,
    ) -> ContactCreateResponse:
        """
        Creates a new contact record.

        After creation, Lightfield automatically enriches the contact in the background.

        Supports idempotency via the `Idempotency-Key` header.

        **[Required scope](/using-the-api/scopes/):** `contacts:create`

        **[Rate limit category](/using-the-api/rate-limits/):** Write

        Args:
          fields: Field values for the new contact. System fields use a `$` prefix (e.g. `$email`,
              `$name`); custom attributes use their bare slug. Note: `$name` is an object
              `{ firstName, lastName }`, not a plain string. Call the
              <u>[definitions endpoint](/api/resources/contact/methods/definitions)</u> to
              discover available fields and their types. See
              <u>[Fields and relationships](/using-the-api/fields-and-relationships/)</u> for
              value type details.

          relationships: Relationships to set on the new contact. System relationships use a `$` prefix
              (e.g. `$account`); custom relationships use their bare slug. Each value is a
              single entity ID or an array of IDs. Call the
              <u>[definitions endpoint](/api/resources/contact/methods/definitions)</u> to
              list available relationship keys.

          extra_headers: Send extra headers

          extra_query: Add additional query parameters to the request

          extra_body: Add additional JSON properties to the request

          timeout: Override the client-level default timeout for this request, in seconds
        """
        return self._post(
            "/v1/contacts",
            body=maybe_transform(
                {
                    "fields": fields,
                    "relationships": relationships,
                },
                contact_create_params.ContactCreateParams,
            ),
            options=make_request_options(
                extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
            ),
            cast_to=ContactCreateResponse,
        )

    def retrieve(
        self,
        id: str,
        *,
        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
        # The extra values given here take precedence over values defined on the client or passed to this method.
        extra_headers: Headers | None = None,
        extra_query: Query | None = None,
        extra_body: Body | None = None,
        timeout: float | httpx.Timeout | None | NotGiven = not_given,
    ) -> ContactRetrieveResponse:
        """
        Retrieves a single contact by its ID.

        **[Required scope](/using-the-api/scopes/):** `contacts:read`

        **[Rate limit category](/using-the-api/rate-limits/):** Read

        Args:
          id: Unique identifier of the contact to retrieve.

          extra_headers: Send extra headers

          extra_query: Add additional query parameters to the request

          extra_body: Add additional JSON properties to the request

          timeout: Override the client-level default timeout for this request, in seconds
        """
        if not id:
            raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
        return self._get(
            path_template("/v1/contacts/{id}", id=id),
            options=make_request_options(
                extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
            ),
            cast_to=ContactRetrieveResponse,
        )

    def update(
        self,
        id: str,
        *,
        fields: contact_update_params.Fields | Omit = omit,
        relationships: contact_update_params.Relationships | Omit = omit,
        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
        # The extra values given here take precedence over values defined on the client or passed to this method.
        extra_headers: Headers | None = None,
        extra_query: Query | None = None,
        extra_body: Body | None = None,
        timeout: float | httpx.Timeout | None | NotGiven = not_given,
    ) -> ContactUpdateResponse:
        """Updates an existing contact by ID.

        Only included fields and relationships are
        modified.

        Supports idempotency via the `Idempotency-Key` header.

        **[Required scope](/using-the-api/scopes/):** `contacts:update`

        **[Rate limit category](/using-the-api/rate-limits/):** Write

        Args:
          id: Unique identifier of the contact to update.

          fields: Field values to update — only provided fields are modified; omitted fields are
              left unchanged. System fields use a `$` prefix (e.g. `$email`); custom
              attributes use their bare slug. Note: `$name` is an object
              `{ firstName, lastName }`, not a plain string. Call the
              <u>[definitions endpoint](/api/resources/contact/methods/definitions)</u> for
              available fields and types. See
              <u>[Fields and relationships](/using-the-api/fields-and-relationships/)</u> for
              value type details.

          relationships: Relationship operations to apply. System relationships use a `$` prefix (e.g.
              `$account`). Each value is an operation object with `add`, `remove`, or
              `replace`.

          extra_headers: Send extra headers

          extra_query: Add additional query parameters to the request

          extra_body: Add additional JSON properties to the request

          timeout: Override the client-level default timeout for this request, in seconds
        """
        if not id:
            raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
        return self._post(
            path_template("/v1/contacts/{id}", id=id),
            body=maybe_transform(
                {
                    "fields": fields,
                    "relationships": relationships,
                },
                contact_update_params.ContactUpdateParams,
            ),
            options=make_request_options(
                extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
            ),
            cast_to=ContactUpdateResponse,
        )

    def list(
        self,
        *,
        limit: int | Omit = omit,
        offset: int | Omit = omit,
        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
        # The extra values given here take precedence over values defined on the client or passed to this method.
        extra_headers: Headers | None = None,
        extra_query: Query | None = None,
        extra_body: Body | None = None,
        timeout: float | httpx.Timeout | None | NotGiven = not_given,
    ) -> ContactListResponse:
        """Returns a paginated list of contacts.

        Use `offset` and `limit` to paginate
        through results. See <u>[List endpoints](/using-the-api/list-endpoints/)</u> for
        more information about pagination.

        **[Required scope](/using-the-api/scopes/):** `contacts:read`

        **[Rate limit category](/using-the-api/rate-limits/):** Search

        Args:
          limit: Maximum number of records to return. Defaults to 25, maximum 25.

          offset: Number of records to skip for pagination. Defaults to 0.

          extra_headers: Send extra headers

          extra_query: Add additional query parameters to the request

          extra_body: Add additional JSON properties to the request

          timeout: Override the client-level default timeout for this request, in seconds
        """
        return self._get(
            "/v1/contacts",
            options=make_request_options(
                extra_headers=extra_headers,
                extra_query=extra_query,
                extra_body=extra_body,
                timeout=timeout,
                query=maybe_transform(
                    {
                        "limit": limit,
                        "offset": offset,
                    },
                    contact_list_params.ContactListParams,
                ),
            ),
            cast_to=ContactListResponse,
        )

    def definitions(
        self,
        *,
        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
        # The extra values given here take precedence over values defined on the client or passed to this method.
        extra_headers: Headers | None = None,
        extra_query: Query | None = None,
        extra_body: Body | None = None,
        timeout: float | httpx.Timeout | None | NotGiven = not_given,
    ) -> ContactDefinitionsResponse:
        """
        Returns the schema for all field and relationship definitions available on
        contacts, including both system-defined and custom fields. Useful for
        understanding the shape of contact data before creating or updating records. See
        <u>[Fields and relationships](/using-the-api/fields-and-relationships/)</u> for
        more details.

        **[Required scope](/using-the-api/scopes/):** `contacts:read`

        **[Rate limit category](/using-the-api/rate-limits/):** Read
        """
        return self._get(
            "/v1/contacts/definitions",
            options=make_request_options(
                extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
            ),
            cast_to=ContactDefinitionsResponse,
        )


class AsyncContactResource(AsyncAPIResource):
    """Contacts represent individual people in Lightfield.

    Contacts can be associated with one or more accounts.
    """

    @cached_property
    def with_raw_response(self) -> AsyncContactResourceWithRawResponse:
        """
        This property can be used as a prefix for any HTTP method call to return
        the raw response object instead of the parsed content.

        For more information, see https://www.github.com/Lightfld/lightfield-python#accessing-raw-response-data-eg-headers
        """
        return AsyncContactResourceWithRawResponse(self)

    @cached_property
    def with_streaming_response(self) -> AsyncContactResourceWithStreamingResponse:
        """
        An alternative to `.with_raw_response` that doesn't eagerly read the response body.

        For more information, see https://www.github.com/Lightfld/lightfield-python#with_streaming_response
        """
        return AsyncContactResourceWithStreamingResponse(self)

    async def create(
        self,
        *,
        fields: contact_create_params.Fields,
        relationships: contact_create_params.Relationships | Omit = omit,
        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
        # The extra values given here take precedence over values defined on the client or passed to this method.
        extra_headers: Headers | None = None,
        extra_query: Query | None = None,
        extra_body: Body | None = None,
        timeout: float | httpx.Timeout | None | NotGiven = not_given,
    ) -> ContactCreateResponse:
        """
        Creates a new contact record.

        After creation, Lightfield automatically enriches the contact in the background.

        Supports idempotency via the `Idempotency-Key` header.

        **[Required scope](/using-the-api/scopes/):** `contacts:create`

        **[Rate limit category](/using-the-api/rate-limits/):** Write

        Args:
          fields: Field values for the new contact. System fields use a `$` prefix (e.g. `$email`,
              `$name`); custom attributes use their bare slug. Note: `$name` is an object
              `{ firstName, lastName }`, not a plain string. Call the
              <u>[definitions endpoint](/api/resources/contact/methods/definitions)</u> to
              discover available fields and their types. See
              <u>[Fields and relationships](/using-the-api/fields-and-relationships/)</u> for
              value type details.

          relationships: Relationships to set on the new contact. System relationships use a `$` prefix
              (e.g. `$account`); custom relationships use their bare slug. Each value is a
              single entity ID or an array of IDs. Call the
              <u>[definitions endpoint](/api/resources/contact/methods/definitions)</u> to
              list available relationship keys.

          extra_headers: Send extra headers

          extra_query: Add additional query parameters to the request

          extra_body: Add additional JSON properties to the request

          timeout: Override the client-level default timeout for this request, in seconds
        """
        return await self._post(
            "/v1/contacts",
            body=await async_maybe_transform(
                {
                    "fields": fields,
                    "relationships": relationships,
                },
                contact_create_params.ContactCreateParams,
            ),
            options=make_request_options(
                extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
            ),
            cast_to=ContactCreateResponse,
        )

    async def retrieve(
        self,
        id: str,
        *,
        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
        # The extra values given here take precedence over values defined on the client or passed to this method.
        extra_headers: Headers | None = None,
        extra_query: Query | None = None,
        extra_body: Body | None = None,
        timeout: float | httpx.Timeout | None | NotGiven = not_given,
    ) -> ContactRetrieveResponse:
        """
        Retrieves a single contact by its ID.

        **[Required scope](/using-the-api/scopes/):** `contacts:read`

        **[Rate limit category](/using-the-api/rate-limits/):** Read

        Args:
          id: Unique identifier of the contact to retrieve.

          extra_headers: Send extra headers

          extra_query: Add additional query parameters to the request

          extra_body: Add additional JSON properties to the request

          timeout: Override the client-level default timeout for this request, in seconds
        """
        if not id:
            raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
        return await self._get(
            path_template("/v1/contacts/{id}", id=id),
            options=make_request_options(
                extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
            ),
            cast_to=ContactRetrieveResponse,
        )

    async def update(
        self,
        id: str,
        *,
        fields: contact_update_params.Fields | Omit = omit,
        relationships: contact_update_params.Relationships | Omit = omit,
        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
        # The extra values given here take precedence over values defined on the client or passed to this method.
        extra_headers: Headers | None = None,
        extra_query: Query | None = None,
        extra_body: Body | None = None,
        timeout: float | httpx.Timeout | None | NotGiven = not_given,
    ) -> ContactUpdateResponse:
        """Updates an existing contact by ID.

        Only included fields and relationships are
        modified.

        Supports idempotency via the `Idempotency-Key` header.

        **[Required scope](/using-the-api/scopes/):** `contacts:update`

        **[Rate limit category](/using-the-api/rate-limits/):** Write

        Args:
          id: Unique identifier of the contact to update.

          fields: Field values to update — only provided fields are modified; omitted fields are
              left unchanged. System fields use a `$` prefix (e.g. `$email`); custom
              attributes use their bare slug. Note: `$name` is an object
              `{ firstName, lastName }`, not a plain string. Call the
              <u>[definitions endpoint](/api/resources/contact/methods/definitions)</u> for
              available fields and types. See
              <u>[Fields and relationships](/using-the-api/fields-and-relationships/)</u> for
              value type details.

          relationships: Relationship operations to apply. System relationships use a `$` prefix (e.g.
              `$account`). Each value is an operation object with `add`, `remove`, or
              `replace`.

          extra_headers: Send extra headers

          extra_query: Add additional query parameters to the request

          extra_body: Add additional JSON properties to the request

          timeout: Override the client-level default timeout for this request, in seconds
        """
        if not id:
            raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
        return await self._post(
            path_template("/v1/contacts/{id}", id=id),
            body=await async_maybe_transform(
                {
                    "fields": fields,
                    "relationships": relationships,
                },
                contact_update_params.ContactUpdateParams,
            ),
            options=make_request_options(
                extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
            ),
            cast_to=ContactUpdateResponse,
        )

    async def list(
        self,
        *,
        limit: int | Omit = omit,
        offset: int | Omit = omit,
        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
        # The extra values given here take precedence over values defined on the client or passed to this method.
        extra_headers: Headers | None = None,
        extra_query: Query | None = None,
        extra_body: Body | None = None,
        timeout: float | httpx.Timeout | None | NotGiven = not_given,
    ) -> ContactListResponse:
        """Returns a paginated list of contacts.

        Use `offset` and `limit` to paginate
        through results. See <u>[List endpoints](/using-the-api/list-endpoints/)</u> for
        more information about pagination.

        **[Required scope](/using-the-api/scopes/):** `contacts:read`

        **[Rate limit category](/using-the-api/rate-limits/):** Search

        Args:
          limit: Maximum number of records to return. Defaults to 25, maximum 25.

          offset: Number of records to skip for pagination. Defaults to 0.

          extra_headers: Send extra headers

          extra_query: Add additional query parameters to the request

          extra_body: Add additional JSON properties to the request

          timeout: Override the client-level default timeout for this request, in seconds
        """
        return await self._get(
            "/v1/contacts",
            options=make_request_options(
                extra_headers=extra_headers,
                extra_query=extra_query,
                extra_body=extra_body,
                timeout=timeout,
                query=await async_maybe_transform(
                    {
                        "limit": limit,
                        "offset": offset,
                    },
                    contact_list_params.ContactListParams,
                ),
            ),
            cast_to=ContactListResponse,
        )

    async def definitions(
        self,
        *,
        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
        # The extra values given here take precedence over values defined on the client or passed to this method.
        extra_headers: Headers | None = None,
        extra_query: Query | None = None,
        extra_body: Body | None = None,
        timeout: float | httpx.Timeout | None | NotGiven = not_given,
    ) -> ContactDefinitionsResponse:
        """
        Returns the schema for all field and relationship definitions available on
        contacts, including both system-defined and custom fields. Useful for
        understanding the shape of contact data before creating or updating records. See
        <u>[Fields and relationships](/using-the-api/fields-and-relationships/)</u> for
        more details.

        **[Required scope](/using-the-api/scopes/):** `contacts:read`

        **[Rate limit category](/using-the-api/rate-limits/):** Read
        """
        return await self._get(
            "/v1/contacts/definitions",
            options=make_request_options(
                extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
            ),
            cast_to=ContactDefinitionsResponse,
        )


class ContactResourceWithRawResponse:
    def __init__(self, contact: ContactResource) -> None:
        self._contact = contact

        self.create = to_raw_response_wrapper(
            contact.create,
        )
        self.retrieve = to_raw_response_wrapper(
            contact.retrieve,
        )
        self.update = to_raw_response_wrapper(
            contact.update,
        )
        self.list = to_raw_response_wrapper(
            contact.list,
        )
        self.definitions = to_raw_response_wrapper(
            contact.definitions,
        )


class AsyncContactResourceWithRawResponse:
    def __init__(self, contact: AsyncContactResource) -> None:
        self._contact = contact

        self.create = async_to_raw_response_wrapper(
            contact.create,
        )
        self.retrieve = async_to_raw_response_wrapper(
            contact.retrieve,
        )
        self.update = async_to_raw_response_wrapper(
            contact.update,
        )
        self.list = async_to_raw_response_wrapper(
            contact.list,
        )
        self.definitions = async_to_raw_response_wrapper(
            contact.definitions,
        )


class ContactResourceWithStreamingResponse:
    def __init__(self, contact: ContactResource) -> None:
        self._contact = contact

        self.create = to_streamed_response_wrapper(
            contact.create,
        )
        self.retrieve = to_streamed_response_wrapper(
            contact.retrieve,
        )
        self.update = to_streamed_response_wrapper(
            contact.update,
        )
        self.list = to_streamed_response_wrapper(
            contact.list,
        )
        self.definitions = to_streamed_response_wrapper(
            contact.definitions,
        )


class AsyncContactResourceWithStreamingResponse:
    def __init__(self, contact: AsyncContactResource) -> None:
        self._contact = contact

        self.create = async_to_streamed_response_wrapper(
            contact.create,
        )
        self.retrieve = async_to_streamed_response_wrapper(
            contact.retrieve,
        )
        self.update = async_to_streamed_response_wrapper(
            contact.update,
        )
        self.list = async_to_streamed_response_wrapper(
            contact.list,
        )
        self.definitions = async_to_streamed_response_wrapper(
            contact.definitions,
        )
