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

import typing
from ....core.client_wrapper import SyncClientWrapper
from .raw_client import RawPromotionsClient
from ....types.loyalty_promotion_status import LoyaltyPromotionStatus
from ....core.request_options import RequestOptions
from ....core.pagination import SyncPager
from ....types.loyalty_promotion import LoyaltyPromotion
from ....core.jsonable_encoder import jsonable_encoder
from ....types.list_loyalty_promotions_response import ListLoyaltyPromotionsResponse
from ....core.unchecked_base_model import construct_type
from json.decoder import JSONDecodeError
from ....core.api_error import ApiError
from ....requests.loyalty_promotion import LoyaltyPromotionParams
from ....types.create_loyalty_promotion_response import CreateLoyaltyPromotionResponse
from ....types.get_loyalty_promotion_response import GetLoyaltyPromotionResponse
from ....types.cancel_loyalty_promotion_response import CancelLoyaltyPromotionResponse
from ....core.client_wrapper import AsyncClientWrapper
from .raw_client import AsyncRawPromotionsClient
from ....core.pagination import AsyncPager

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


class PromotionsClient:
    def __init__(self, *, client_wrapper: SyncClientWrapper):
        self._raw_client = RawPromotionsClient(client_wrapper=client_wrapper)

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

        Returns
        -------
        RawPromotionsClient
        """
        return self._raw_client

    def list(
        self,
        program_id: str,
        *,
        status: typing.Optional[LoyaltyPromotionStatus] = None,
        cursor: typing.Optional[str] = None,
        limit: typing.Optional[int] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> SyncPager[LoyaltyPromotion]:
        """
        Lists the loyalty promotions associated with a [loyalty program](entity:LoyaltyProgram).
        Results are sorted by the `created_at` date in descending order (newest to oldest).

        Parameters
        ----------
        program_id : str
            The ID of the base [loyalty program](entity:LoyaltyProgram). To get the program ID,
            call [RetrieveLoyaltyProgram](api-endpoint:Loyalty-RetrieveLoyaltyProgram) using the `main` keyword.

        status : typing.Optional[LoyaltyPromotionStatus]
            The status to filter the results by. If a status is provided, only loyalty promotions
            with the specified status are returned. Otherwise, all loyalty promotions associated with
            the loyalty program are returned.

        cursor : typing.Optional[str]
            The cursor returned in the paged response from the previous call to this endpoint.
            Provide this cursor to retrieve the next page of results for your original request.
            For more information, see [Pagination](https://developer.squareup.com/docs/build-basics/common-api-patterns/pagination).

        limit : typing.Optional[int]
            The maximum number of results to return in a single paged response.
            The minimum value is 1 and the maximum value is 30. The default value is 30.
            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
        -------
        SyncPager[LoyaltyPromotion]
            Success

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

        client = Square(
            token="YOUR_TOKEN",
        )
        response = client.loyalty.programs.promotions.list(
            program_id="program_id",
        )
        for item in response:
            yield item
        # alternatively, you can paginate page-by-page
        for page in response.iter_pages():
            yield page
        """
        _response = self._raw_client._client_wrapper.httpx_client.request(
            f"v2/loyalty/programs/{jsonable_encoder(program_id)}/promotions",
            method="GET",
            params={
                "status": status,
                "cursor": cursor,
                "limit": limit,
            },
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _parsed_response = typing.cast(
                    ListLoyaltyPromotionsResponse,
                    construct_type(
                        type_=ListLoyaltyPromotionsResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                _parsed_next = _parsed_response.cursor
                _has_next = _parsed_next is not None and _parsed_next != ""
                _get_next = lambda: self.list(
                    program_id,
                    status=status,
                    cursor=_parsed_next,
                    limit=limit,
                    request_options=request_options,
                )
                _items = _parsed_response.loyalty_promotions
                return SyncPager(has_next=_has_next, items=_items, get_next=_get_next)
            _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 create(
        self,
        program_id: str,
        *,
        loyalty_promotion: LoyaltyPromotionParams,
        idempotency_key: str,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> CreateLoyaltyPromotionResponse:
        """
        Creates a loyalty promotion for a [loyalty program](entity:LoyaltyProgram). A loyalty promotion
        enables buyers to earn points in addition to those earned from the base loyalty program.

        This endpoint sets the loyalty promotion to the `ACTIVE` or `SCHEDULED` status, depending on the
        `available_time` setting. A loyalty program can have a maximum of 10 loyalty promotions with an
        `ACTIVE` or `SCHEDULED` status.

        Parameters
        ----------
        program_id : str
            The ID of the [loyalty program](entity:LoyaltyProgram) to associate with the promotion.
            To get the program ID, call [RetrieveLoyaltyProgram](api-endpoint:Loyalty-RetrieveLoyaltyProgram)
            using the `main` keyword.

        loyalty_promotion : LoyaltyPromotionParams
            The loyalty promotion to create.

        idempotency_key : str
            A unique identifier for this request, which is used to ensure idempotency. For more information,
            see [Idempotency](https://developer.squareup.com/docs/build-basics/common-api-patterns/idempotency).

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

        Returns
        -------
        CreateLoyaltyPromotionResponse
            Success

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

        client = Square(
            token="YOUR_TOKEN",
        )
        client.loyalty.programs.promotions.create(
            program_id="program_id",
            loyalty_promotion={
                "name": "Tuesday Happy Hour Promo",
                "incentive": {
                    "type": "POINTS_MULTIPLIER",
                    "points_multiplier_data": {"multiplier": "3.0"},
                },
                "available_time": {
                    "time_periods": [
                        "BEGIN:VEVENT\nDTSTART:20220816T160000\nDURATION:PT2H\nRRULE:FREQ=WEEKLY;BYDAY=TU\nEND:VEVENT"
                    ]
                },
                "trigger_limit": {"times": 1, "interval": "DAY"},
                "minimum_spend_amount_money": {"amount": 2000, "currency": "USD"},
                "qualifying_category_ids": ["XTQPYLR3IIU9C44VRCB3XD12"],
            },
            idempotency_key="ec78c477-b1c3-4899-a209-a4e71337c996",
        )
        """
        response = self._raw_client.create(
            program_id,
            loyalty_promotion=loyalty_promotion,
            idempotency_key=idempotency_key,
            request_options=request_options,
        )
        return response.data

    def get(
        self, promotion_id: str, program_id: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> GetLoyaltyPromotionResponse:
        """
        Retrieves a loyalty promotion.

        Parameters
        ----------
        promotion_id : str
            The ID of the [loyalty promotion](entity:LoyaltyPromotion) to retrieve.

        program_id : str
            The ID of the base [loyalty program](entity:LoyaltyProgram). To get the program ID,
            call [RetrieveLoyaltyProgram](api-endpoint:Loyalty-RetrieveLoyaltyProgram) using the `main` keyword.

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

        Returns
        -------
        GetLoyaltyPromotionResponse
            Success

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

        client = Square(
            token="YOUR_TOKEN",
        )
        client.loyalty.programs.promotions.get(
            promotion_id="promotion_id",
            program_id="program_id",
        )
        """
        response = self._raw_client.get(promotion_id, program_id, request_options=request_options)
        return response.data

    def cancel(
        self, promotion_id: str, program_id: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> CancelLoyaltyPromotionResponse:
        """
        Cancels a loyalty promotion. Use this endpoint to cancel an `ACTIVE` promotion earlier than the
        end date, cancel an `ACTIVE` promotion when an end date is not specified, or cancel a `SCHEDULED` promotion.
        Because updating a promotion is not supported, you can also use this endpoint to cancel a promotion before
        you create a new one.

        This endpoint sets the loyalty promotion to the `CANCELED` state

        Parameters
        ----------
        promotion_id : str
            The ID of the [loyalty promotion](entity:LoyaltyPromotion) to cancel. You can cancel a
            promotion that has an `ACTIVE` or `SCHEDULED` status.

        program_id : str
            The ID of the base [loyalty program](entity:LoyaltyProgram).

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

        Returns
        -------
        CancelLoyaltyPromotionResponse
            Success

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

        client = Square(
            token="YOUR_TOKEN",
        )
        client.loyalty.programs.promotions.cancel(
            promotion_id="promotion_id",
            program_id="program_id",
        )
        """
        response = self._raw_client.cancel(promotion_id, program_id, request_options=request_options)
        return response.data


class AsyncPromotionsClient:
    def __init__(self, *, client_wrapper: AsyncClientWrapper):
        self._raw_client = AsyncRawPromotionsClient(client_wrapper=client_wrapper)

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

        Returns
        -------
        AsyncRawPromotionsClient
        """
        return self._raw_client

    async def list(
        self,
        program_id: str,
        *,
        status: typing.Optional[LoyaltyPromotionStatus] = None,
        cursor: typing.Optional[str] = None,
        limit: typing.Optional[int] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncPager[LoyaltyPromotion]:
        """
        Lists the loyalty promotions associated with a [loyalty program](entity:LoyaltyProgram).
        Results are sorted by the `created_at` date in descending order (newest to oldest).

        Parameters
        ----------
        program_id : str
            The ID of the base [loyalty program](entity:LoyaltyProgram). To get the program ID,
            call [RetrieveLoyaltyProgram](api-endpoint:Loyalty-RetrieveLoyaltyProgram) using the `main` keyword.

        status : typing.Optional[LoyaltyPromotionStatus]
            The status to filter the results by. If a status is provided, only loyalty promotions
            with the specified status are returned. Otherwise, all loyalty promotions associated with
            the loyalty program are returned.

        cursor : typing.Optional[str]
            The cursor returned in the paged response from the previous call to this endpoint.
            Provide this cursor to retrieve the next page of results for your original request.
            For more information, see [Pagination](https://developer.squareup.com/docs/build-basics/common-api-patterns/pagination).

        limit : typing.Optional[int]
            The maximum number of results to return in a single paged response.
            The minimum value is 1 and the maximum value is 30. The default value is 30.
            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
        -------
        AsyncPager[LoyaltyPromotion]
            Success

        Examples
        --------
        import asyncio

        from square import AsyncSquare

        client = AsyncSquare(
            token="YOUR_TOKEN",
        )


        async def main() -> None:
            response = await client.loyalty.programs.promotions.list(
                program_id="program_id",
            )
            async for item in response:
                yield item
            # alternatively, you can paginate page-by-page
            async for page in response.iter_pages():
                yield page


        asyncio.run(main())
        """
        _response = await self._raw_client._client_wrapper.httpx_client.request(
            f"v2/loyalty/programs/{jsonable_encoder(program_id)}/promotions",
            method="GET",
            params={
                "status": status,
                "cursor": cursor,
                "limit": limit,
            },
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _parsed_response = typing.cast(
                    ListLoyaltyPromotionsResponse,
                    construct_type(
                        type_=ListLoyaltyPromotionsResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                _parsed_next = _parsed_response.cursor
                _has_next = _parsed_next is not None and _parsed_next != ""
                _get_next = lambda: self.list(
                    program_id,
                    status=status,
                    cursor=_parsed_next,
                    limit=limit,
                    request_options=request_options,
                )
                _items = _parsed_response.loyalty_promotions
                return AsyncPager(has_next=_has_next, items=_items, get_next=_get_next)
            _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 create(
        self,
        program_id: str,
        *,
        loyalty_promotion: LoyaltyPromotionParams,
        idempotency_key: str,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> CreateLoyaltyPromotionResponse:
        """
        Creates a loyalty promotion for a [loyalty program](entity:LoyaltyProgram). A loyalty promotion
        enables buyers to earn points in addition to those earned from the base loyalty program.

        This endpoint sets the loyalty promotion to the `ACTIVE` or `SCHEDULED` status, depending on the
        `available_time` setting. A loyalty program can have a maximum of 10 loyalty promotions with an
        `ACTIVE` or `SCHEDULED` status.

        Parameters
        ----------
        program_id : str
            The ID of the [loyalty program](entity:LoyaltyProgram) to associate with the promotion.
            To get the program ID, call [RetrieveLoyaltyProgram](api-endpoint:Loyalty-RetrieveLoyaltyProgram)
            using the `main` keyword.

        loyalty_promotion : LoyaltyPromotionParams
            The loyalty promotion to create.

        idempotency_key : str
            A unique identifier for this request, which is used to ensure idempotency. For more information,
            see [Idempotency](https://developer.squareup.com/docs/build-basics/common-api-patterns/idempotency).

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

        Returns
        -------
        CreateLoyaltyPromotionResponse
            Success

        Examples
        --------
        import asyncio

        from square import AsyncSquare

        client = AsyncSquare(
            token="YOUR_TOKEN",
        )


        async def main() -> None:
            await client.loyalty.programs.promotions.create(
                program_id="program_id",
                loyalty_promotion={
                    "name": "Tuesday Happy Hour Promo",
                    "incentive": {
                        "type": "POINTS_MULTIPLIER",
                        "points_multiplier_data": {"multiplier": "3.0"},
                    },
                    "available_time": {
                        "time_periods": [
                            "BEGIN:VEVENT\nDTSTART:20220816T160000\nDURATION:PT2H\nRRULE:FREQ=WEEKLY;BYDAY=TU\nEND:VEVENT"
                        ]
                    },
                    "trigger_limit": {"times": 1, "interval": "DAY"},
                    "minimum_spend_amount_money": {"amount": 2000, "currency": "USD"},
                    "qualifying_category_ids": ["XTQPYLR3IIU9C44VRCB3XD12"],
                },
                idempotency_key="ec78c477-b1c3-4899-a209-a4e71337c996",
            )


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

    async def get(
        self, promotion_id: str, program_id: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> GetLoyaltyPromotionResponse:
        """
        Retrieves a loyalty promotion.

        Parameters
        ----------
        promotion_id : str
            The ID of the [loyalty promotion](entity:LoyaltyPromotion) to retrieve.

        program_id : str
            The ID of the base [loyalty program](entity:LoyaltyProgram). To get the program ID,
            call [RetrieveLoyaltyProgram](api-endpoint:Loyalty-RetrieveLoyaltyProgram) using the `main` keyword.

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

        Returns
        -------
        GetLoyaltyPromotionResponse
            Success

        Examples
        --------
        import asyncio

        from square import AsyncSquare

        client = AsyncSquare(
            token="YOUR_TOKEN",
        )


        async def main() -> None:
            await client.loyalty.programs.promotions.get(
                promotion_id="promotion_id",
                program_id="program_id",
            )


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

    async def cancel(
        self, promotion_id: str, program_id: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> CancelLoyaltyPromotionResponse:
        """
        Cancels a loyalty promotion. Use this endpoint to cancel an `ACTIVE` promotion earlier than the
        end date, cancel an `ACTIVE` promotion when an end date is not specified, or cancel a `SCHEDULED` promotion.
        Because updating a promotion is not supported, you can also use this endpoint to cancel a promotion before
        you create a new one.

        This endpoint sets the loyalty promotion to the `CANCELED` state

        Parameters
        ----------
        promotion_id : str
            The ID of the [loyalty promotion](entity:LoyaltyPromotion) to cancel. You can cancel a
            promotion that has an `ACTIVE` or `SCHEDULED` status.

        program_id : str
            The ID of the base [loyalty program](entity:LoyaltyProgram).

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

        Returns
        -------
        CancelLoyaltyPromotionResponse
            Success

        Examples
        --------
        import asyncio

        from square import AsyncSquare

        client = AsyncSquare(
            token="YOUR_TOKEN",
        )


        async def main() -> None:
            await client.loyalty.programs.promotions.cancel(
                promotion_id="promotion_id",
                program_id="program_id",
            )


        asyncio.run(main())
        """
        response = await self._raw_client.cancel(promotion_id, program_id, request_options=request_options)
        return response.data
