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

import typing
from ...core.client_wrapper import SyncClientWrapper
from .raw_client import RawAccountsClient
from ...requests.loyalty_account import LoyaltyAccountParams
from ...core.request_options import RequestOptions
from ...types.create_loyalty_account_response import CreateLoyaltyAccountResponse
from ...requests.search_loyalty_accounts_request_loyalty_account_query import (
    SearchLoyaltyAccountsRequestLoyaltyAccountQueryParams,
)
from ...types.search_loyalty_accounts_response import SearchLoyaltyAccountsResponse
from ...types.get_loyalty_account_response import GetLoyaltyAccountResponse
from ...requests.loyalty_event_accumulate_points import LoyaltyEventAccumulatePointsParams
from ...types.accumulate_loyalty_points_response import AccumulateLoyaltyPointsResponse
from ...requests.loyalty_event_adjust_points import LoyaltyEventAdjustPointsParams
from ...types.adjust_loyalty_points_response import AdjustLoyaltyPointsResponse
from ...core.client_wrapper import AsyncClientWrapper
from .raw_client import AsyncRawAccountsClient

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


class AccountsClient:
    def __init__(self, *, client_wrapper: SyncClientWrapper):
        self._raw_client = RawAccountsClient(client_wrapper=client_wrapper)

    @property
    def with_raw_response(self) -> RawAccountsClient:
        """
        Retrieves a raw implementation of this client that returns raw responses.

        Returns
        -------
        RawAccountsClient
        """
        return self._raw_client

    def create(
        self,
        *,
        loyalty_account: LoyaltyAccountParams,
        idempotency_key: str,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> CreateLoyaltyAccountResponse:
        """
        Creates a loyalty account. To create a loyalty account, you must provide the `program_id` and a `mapping` with the `phone_number` of the buyer.

        Parameters
        ----------
        loyalty_account : LoyaltyAccountParams
            The loyalty account to create.

        idempotency_key : str
            A unique string that identifies this `CreateLoyaltyAccount` request.
            Keys can be any valid string, but must be unique for every request.

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

        Returns
        -------
        CreateLoyaltyAccountResponse
            Success

        Examples
        --------
        from square import Square

        client = Square(
            token="YOUR_TOKEN",
        )
        client.loyalty.accounts.create(
            loyalty_account={
                "program_id": "d619f755-2d17-41f3-990d-c04ecedd64dd",
                "mapping": {"phone_number": "+14155551234"},
            },
            idempotency_key="ec78c477-b1c3-4899-a209-a4e71337c996",
        )
        """
        response = self._raw_client.create(
            loyalty_account=loyalty_account, idempotency_key=idempotency_key, request_options=request_options
        )
        return response.data

    def search(
        self,
        *,
        query: typing.Optional[SearchLoyaltyAccountsRequestLoyaltyAccountQueryParams] = OMIT,
        limit: typing.Optional[int] = OMIT,
        cursor: typing.Optional[str] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> SearchLoyaltyAccountsResponse:
        """
        Searches for loyalty accounts in a loyalty program.

        You can search for a loyalty account using the phone number or customer ID associated with the account. To return all loyalty accounts, specify an empty `query` object or omit it entirely.

        Search results are sorted by `created_at` in ascending order.

        Parameters
        ----------
        query : typing.Optional[SearchLoyaltyAccountsRequestLoyaltyAccountQueryParams]
            The search criteria for the request.

        limit : typing.Optional[int]
            The maximum number of results to include in the response. The default value is 30.

        cursor : typing.Optional[str]
            A pagination cursor returned by a previous call to
            this endpoint. Provide this to retrieve the next set of
            results for the original query.

            For more information,
            see [Pagination](https://developer.squareup.com/docs/build-basics/common-api-patterns/pagination).

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

        Returns
        -------
        SearchLoyaltyAccountsResponse
            Success

        Examples
        --------
        from square import Square

        client = Square(
            token="YOUR_TOKEN",
        )
        client.loyalty.accounts.search(
            query={"mappings": [{"phone_number": "+14155551234"}]},
            limit=10,
        )
        """
        response = self._raw_client.search(query=query, limit=limit, cursor=cursor, request_options=request_options)
        return response.data

    def get(
        self, account_id: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> GetLoyaltyAccountResponse:
        """
        Retrieves a loyalty account.

        Parameters
        ----------
        account_id : str
            The ID of the [loyalty account](entity:LoyaltyAccount) to retrieve.

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

        Returns
        -------
        GetLoyaltyAccountResponse
            Success

        Examples
        --------
        from square import Square

        client = Square(
            token="YOUR_TOKEN",
        )
        client.loyalty.accounts.get(
            account_id="account_id",
        )
        """
        response = self._raw_client.get(account_id, request_options=request_options)
        return response.data

    def accumulate_points(
        self,
        account_id: str,
        *,
        accumulate_points: LoyaltyEventAccumulatePointsParams,
        idempotency_key: str,
        location_id: str,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AccumulateLoyaltyPointsResponse:
        """
        Adds points earned from a purchase to a [loyalty account](entity:LoyaltyAccount).

        - If you are using the Orders API to manage orders, provide the `order_id`. Square reads the order
        to compute the points earned from both the base loyalty program and an associated
        [loyalty promotion](entity:LoyaltyPromotion). For purchases that qualify for multiple accrual
        rules, Square computes points based on the accrual rule that grants the most points.
        For purchases that qualify for multiple promotions, Square computes points based on the most
        recently created promotion. A purchase must first qualify for program points to be eligible for promotion points.

        - If you are not using the Orders API to manage orders, provide `points` with the number of points to add.
        You must first perform a client-side computation of the points earned from the loyalty program and
        loyalty promotion. For spend-based and visit-based programs, you can call [CalculateLoyaltyPoints](api-endpoint:Loyalty-CalculateLoyaltyPoints)
        to compute the points earned from the base loyalty program. For information about computing points earned from a loyalty promotion, see
        [Calculating promotion points](https://developer.squareup.com/docs/loyalty-api/loyalty-promotions#calculate-promotion-points).

        Parameters
        ----------
        account_id : str
            The ID of the target [loyalty account](entity:LoyaltyAccount).

        accumulate_points : LoyaltyEventAccumulatePointsParams
            The points to add to the account.
            If you are using the Orders API to manage orders, specify the order ID.
            Otherwise, specify the points to add.

        idempotency_key : str
            A unique string that identifies the `AccumulateLoyaltyPoints` request.
            Keys can be any valid string but must be unique for every request.

        location_id : str
            The [location](entity:Location) where the purchase was made.

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

        Returns
        -------
        AccumulateLoyaltyPointsResponse
            Success

        Examples
        --------
        from square import Square

        client = Square(
            token="YOUR_TOKEN",
        )
        client.loyalty.accounts.accumulate_points(
            account_id="account_id",
            accumulate_points={"order_id": "RFZfrdtm3mhO1oGzf5Cx7fEMsmGZY"},
            idempotency_key="58b90739-c3e8-4b11-85f7-e636d48d72cb",
            location_id="P034NEENMD09F",
        )
        """
        response = self._raw_client.accumulate_points(
            account_id,
            accumulate_points=accumulate_points,
            idempotency_key=idempotency_key,
            location_id=location_id,
            request_options=request_options,
        )
        return response.data

    def adjust(
        self,
        account_id: str,
        *,
        idempotency_key: str,
        adjust_points: LoyaltyEventAdjustPointsParams,
        allow_negative_balance: typing.Optional[bool] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AdjustLoyaltyPointsResponse:
        """
        Adds points to or subtracts points from a buyer's account.

        Use this endpoint only when you need to manually adjust points. Otherwise, in your application flow, you call
        [AccumulateLoyaltyPoints](api-endpoint:Loyalty-AccumulateLoyaltyPoints)
        to add points when a buyer pays for the purchase.

        Parameters
        ----------
        account_id : str
            The ID of the target [loyalty account](entity:LoyaltyAccount).

        idempotency_key : str
            A unique string that identifies this `AdjustLoyaltyPoints` request.
            Keys can be any valid string, but must be unique for every request.

        adjust_points : LoyaltyEventAdjustPointsParams
            The points to add or subtract and the reason for the adjustment. To add points, specify a positive integer.
            To subtract points, specify a negative integer.

        allow_negative_balance : typing.Optional[bool]
            Indicates whether to allow a negative adjustment to result in a negative balance. If `true`, a negative
            balance is allowed when subtracting points. If `false`, Square returns a `BAD_REQUEST` error when subtracting
            the specified number of points would result in a negative balance. The default value is `false`.

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

        Returns
        -------
        AdjustLoyaltyPointsResponse
            Success

        Examples
        --------
        from square import Square

        client = Square(
            token="YOUR_TOKEN",
        )
        client.loyalty.accounts.adjust(
            account_id="account_id",
            idempotency_key="bc29a517-3dc9-450e-aa76-fae39ee849d1",
            adjust_points={"points": 10, "reason": "Complimentary points"},
        )
        """
        response = self._raw_client.adjust(
            account_id,
            idempotency_key=idempotency_key,
            adjust_points=adjust_points,
            allow_negative_balance=allow_negative_balance,
            request_options=request_options,
        )
        return response.data


class AsyncAccountsClient:
    def __init__(self, *, client_wrapper: AsyncClientWrapper):
        self._raw_client = AsyncRawAccountsClient(client_wrapper=client_wrapper)

    @property
    def with_raw_response(self) -> AsyncRawAccountsClient:
        """
        Retrieves a raw implementation of this client that returns raw responses.

        Returns
        -------
        AsyncRawAccountsClient
        """
        return self._raw_client

    async def create(
        self,
        *,
        loyalty_account: LoyaltyAccountParams,
        idempotency_key: str,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> CreateLoyaltyAccountResponse:
        """
        Creates a loyalty account. To create a loyalty account, you must provide the `program_id` and a `mapping` with the `phone_number` of the buyer.

        Parameters
        ----------
        loyalty_account : LoyaltyAccountParams
            The loyalty account to create.

        idempotency_key : str
            A unique string that identifies this `CreateLoyaltyAccount` request.
            Keys can be any valid string, but must be unique for every request.

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

        Returns
        -------
        CreateLoyaltyAccountResponse
            Success

        Examples
        --------
        import asyncio

        from square import AsyncSquare

        client = AsyncSquare(
            token="YOUR_TOKEN",
        )


        async def main() -> None:
            await client.loyalty.accounts.create(
                loyalty_account={
                    "program_id": "d619f755-2d17-41f3-990d-c04ecedd64dd",
                    "mapping": {"phone_number": "+14155551234"},
                },
                idempotency_key="ec78c477-b1c3-4899-a209-a4e71337c996",
            )


        asyncio.run(main())
        """
        response = await self._raw_client.create(
            loyalty_account=loyalty_account, idempotency_key=idempotency_key, request_options=request_options
        )
        return response.data

    async def search(
        self,
        *,
        query: typing.Optional[SearchLoyaltyAccountsRequestLoyaltyAccountQueryParams] = OMIT,
        limit: typing.Optional[int] = OMIT,
        cursor: typing.Optional[str] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> SearchLoyaltyAccountsResponse:
        """
        Searches for loyalty accounts in a loyalty program.

        You can search for a loyalty account using the phone number or customer ID associated with the account. To return all loyalty accounts, specify an empty `query` object or omit it entirely.

        Search results are sorted by `created_at` in ascending order.

        Parameters
        ----------
        query : typing.Optional[SearchLoyaltyAccountsRequestLoyaltyAccountQueryParams]
            The search criteria for the request.

        limit : typing.Optional[int]
            The maximum number of results to include in the response. The default value is 30.

        cursor : typing.Optional[str]
            A pagination cursor returned by a previous call to
            this endpoint. Provide this to retrieve the next set of
            results for the original query.

            For more information,
            see [Pagination](https://developer.squareup.com/docs/build-basics/common-api-patterns/pagination).

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

        Returns
        -------
        SearchLoyaltyAccountsResponse
            Success

        Examples
        --------
        import asyncio

        from square import AsyncSquare

        client = AsyncSquare(
            token="YOUR_TOKEN",
        )


        async def main() -> None:
            await client.loyalty.accounts.search(
                query={"mappings": [{"phone_number": "+14155551234"}]},
                limit=10,
            )


        asyncio.run(main())
        """
        response = await self._raw_client.search(
            query=query, limit=limit, cursor=cursor, request_options=request_options
        )
        return response.data

    async def get(
        self, account_id: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> GetLoyaltyAccountResponse:
        """
        Retrieves a loyalty account.

        Parameters
        ----------
        account_id : str
            The ID of the [loyalty account](entity:LoyaltyAccount) to retrieve.

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

        Returns
        -------
        GetLoyaltyAccountResponse
            Success

        Examples
        --------
        import asyncio

        from square import AsyncSquare

        client = AsyncSquare(
            token="YOUR_TOKEN",
        )


        async def main() -> None:
            await client.loyalty.accounts.get(
                account_id="account_id",
            )


        asyncio.run(main())
        """
        response = await self._raw_client.get(account_id, request_options=request_options)
        return response.data

    async def accumulate_points(
        self,
        account_id: str,
        *,
        accumulate_points: LoyaltyEventAccumulatePointsParams,
        idempotency_key: str,
        location_id: str,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AccumulateLoyaltyPointsResponse:
        """
        Adds points earned from a purchase to a [loyalty account](entity:LoyaltyAccount).

        - If you are using the Orders API to manage orders, provide the `order_id`. Square reads the order
        to compute the points earned from both the base loyalty program and an associated
        [loyalty promotion](entity:LoyaltyPromotion). For purchases that qualify for multiple accrual
        rules, Square computes points based on the accrual rule that grants the most points.
        For purchases that qualify for multiple promotions, Square computes points based on the most
        recently created promotion. A purchase must first qualify for program points to be eligible for promotion points.

        - If you are not using the Orders API to manage orders, provide `points` with the number of points to add.
        You must first perform a client-side computation of the points earned from the loyalty program and
        loyalty promotion. For spend-based and visit-based programs, you can call [CalculateLoyaltyPoints](api-endpoint:Loyalty-CalculateLoyaltyPoints)
        to compute the points earned from the base loyalty program. For information about computing points earned from a loyalty promotion, see
        [Calculating promotion points](https://developer.squareup.com/docs/loyalty-api/loyalty-promotions#calculate-promotion-points).

        Parameters
        ----------
        account_id : str
            The ID of the target [loyalty account](entity:LoyaltyAccount).

        accumulate_points : LoyaltyEventAccumulatePointsParams
            The points to add to the account.
            If you are using the Orders API to manage orders, specify the order ID.
            Otherwise, specify the points to add.

        idempotency_key : str
            A unique string that identifies the `AccumulateLoyaltyPoints` request.
            Keys can be any valid string but must be unique for every request.

        location_id : str
            The [location](entity:Location) where the purchase was made.

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

        Returns
        -------
        AccumulateLoyaltyPointsResponse
            Success

        Examples
        --------
        import asyncio

        from square import AsyncSquare

        client = AsyncSquare(
            token="YOUR_TOKEN",
        )


        async def main() -> None:
            await client.loyalty.accounts.accumulate_points(
                account_id="account_id",
                accumulate_points={"order_id": "RFZfrdtm3mhO1oGzf5Cx7fEMsmGZY"},
                idempotency_key="58b90739-c3e8-4b11-85f7-e636d48d72cb",
                location_id="P034NEENMD09F",
            )


        asyncio.run(main())
        """
        response = await self._raw_client.accumulate_points(
            account_id,
            accumulate_points=accumulate_points,
            idempotency_key=idempotency_key,
            location_id=location_id,
            request_options=request_options,
        )
        return response.data

    async def adjust(
        self,
        account_id: str,
        *,
        idempotency_key: str,
        adjust_points: LoyaltyEventAdjustPointsParams,
        allow_negative_balance: typing.Optional[bool] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AdjustLoyaltyPointsResponse:
        """
        Adds points to or subtracts points from a buyer's account.

        Use this endpoint only when you need to manually adjust points. Otherwise, in your application flow, you call
        [AccumulateLoyaltyPoints](api-endpoint:Loyalty-AccumulateLoyaltyPoints)
        to add points when a buyer pays for the purchase.

        Parameters
        ----------
        account_id : str
            The ID of the target [loyalty account](entity:LoyaltyAccount).

        idempotency_key : str
            A unique string that identifies this `AdjustLoyaltyPoints` request.
            Keys can be any valid string, but must be unique for every request.

        adjust_points : LoyaltyEventAdjustPointsParams
            The points to add or subtract and the reason for the adjustment. To add points, specify a positive integer.
            To subtract points, specify a negative integer.

        allow_negative_balance : typing.Optional[bool]
            Indicates whether to allow a negative adjustment to result in a negative balance. If `true`, a negative
            balance is allowed when subtracting points. If `false`, Square returns a `BAD_REQUEST` error when subtracting
            the specified number of points would result in a negative balance. The default value is `false`.

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

        Returns
        -------
        AdjustLoyaltyPointsResponse
            Success

        Examples
        --------
        import asyncio

        from square import AsyncSquare

        client = AsyncSquare(
            token="YOUR_TOKEN",
        )


        async def main() -> None:
            await client.loyalty.accounts.adjust(
                account_id="account_id",
                idempotency_key="bc29a517-3dc9-450e-aa76-fae39ee849d1",
                adjust_points={"points": 10, "reason": "Complimentary points"},
            )


        asyncio.run(main())
        """
        response = await self._raw_client.adjust(
            account_id,
            idempotency_key=idempotency_key,
            adjust_points=adjust_points,
            allow_negative_balance=allow_negative_balance,
            request_options=request_options,
        )
        return response.data
