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

import typing
from ..core.client_wrapper import SyncClientWrapper
from ..requests.money import MoneyParams
from ..requests.destination_details_cash_refund_details import DestinationDetailsCashRefundDetailsParams
from ..requests.destination_details_external_refund_details import DestinationDetailsExternalRefundDetailsParams
from ..core.request_options import RequestOptions
from ..core.http_response import HttpResponse
from ..types.refund_payment_response import RefundPaymentResponse
from ..core.serialization import convert_and_respect_annotation_metadata
from ..core.unchecked_base_model import construct_type
from json.decoder import JSONDecodeError
from ..core.api_error import ApiError
from ..types.get_payment_refund_response import GetPaymentRefundResponse
from ..core.jsonable_encoder import jsonable_encoder
from ..core.client_wrapper import AsyncClientWrapper
from ..core.http_response import AsyncHttpResponse

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


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

    def refund_payment(
        self,
        *,
        idempotency_key: str,
        amount_money: MoneyParams,
        app_fee_money: typing.Optional[MoneyParams] = OMIT,
        payment_id: typing.Optional[str] = OMIT,
        destination_id: typing.Optional[str] = OMIT,
        unlinked: typing.Optional[bool] = OMIT,
        location_id: typing.Optional[str] = OMIT,
        customer_id: typing.Optional[str] = OMIT,
        reason: typing.Optional[str] = OMIT,
        payment_version_token: typing.Optional[str] = OMIT,
        team_member_id: typing.Optional[str] = OMIT,
        cash_details: typing.Optional[DestinationDetailsCashRefundDetailsParams] = OMIT,
        external_details: typing.Optional[DestinationDetailsExternalRefundDetailsParams] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> HttpResponse[RefundPaymentResponse]:
        """
        Refunds a payment. You can refund the entire payment amount or a
        portion of it. You can use this endpoint to refund a card payment or record a
        refund of a cash or external payment. For more information, see
        [Refund Payment](https://developer.squareup.com/docs/payments-api/refund-payments).

        Parameters
        ----------
        idempotency_key : str
             A unique string that identifies this `RefundPayment` request. The key can be any valid string
            but must be unique for every `RefundPayment` request.

            Keys are limited to a max of 45 characters - however, the number of allowed characters might be
            less than 45, if multi-byte characters are used.

            For more information, see [Idempotency](https://developer.squareup.com/docs/working-with-apis/idempotency).

        amount_money : MoneyParams
            The amount of money to refund.

            This amount cannot be more than the `total_money` value of the payment minus the total
            amount of all previously completed refunds for this payment.

            This amount must be specified in the smallest denomination of the applicable currency
            (for example, US dollar amounts are specified in cents). For more information, see
            [Working with Monetary Amounts](https://developer.squareup.com/docs/build-basics/working-with-monetary-amounts).

            The currency code must match the currency associated with the business
            that is charging the card.

        app_fee_money : typing.Optional[MoneyParams]
            The amount of money the developer contributes to help cover the refunded amount.
            This amount is specified in the smallest denomination of the applicable currency (for example,
            US dollar amounts are specified in cents).

            The value cannot be more than the `amount_money`.

            You can specify this parameter in a refund request only if the same parameter was also included
            when taking the payment. This is part of the application fee scenario the API supports. For more
            information, see [Take Payments and Collect Fees](https://developer.squareup.com/docs/payments-api/take-payments-and-collect-fees).

            To set this field, `PAYMENTS_WRITE_ADDITIONAL_RECIPIENTS` OAuth permission is required.
            For more information, see [Permissions](https://developer.squareup.com/docs/payments-api/take-payments-and-collect-fees#permissions).

        payment_id : typing.Optional[str]
            The unique ID of the payment being refunded.
            Required when unlinked=false, otherwise must not be set.

        destination_id : typing.Optional[str]
            The ID indicating where funds will be refunded to. Required for unlinked refunds. For more
            information, see [Process an Unlinked Refund](https://developer.squareup.com/docs/refunds-api/unlinked-refunds).

            For refunds linked to Square payments, `destination_id` is usually omitted; in this case, funds
            will be returned to the original payment source. The field may be specified in order to request
            a cross-method refund to a gift card. For more information,
            see [Cross-method refunds to gift cards](https://developer.squareup.com/docs/payments-api/refund-payments#cross-method-refunds-to-gift-cards).

        unlinked : typing.Optional[bool]
            Indicates that the refund is not linked to a Square payment.
            If set to true, `destination_id` and `location_id` must be supplied while `payment_id` must not
            be provided.

        location_id : typing.Optional[str]
            The location ID associated with the unlinked refund.
            Required for requests specifying `unlinked=true`.
            Otherwise, if included when `unlinked=false`, will throw an error.

        customer_id : typing.Optional[str]
            The [Customer](entity:Customer) ID of the customer associated with the refund.
            This is required if the `destination_id` refers to a card on file created using the Cards
            API. Only allowed when `unlinked=true`.

        reason : typing.Optional[str]
            A description of the reason for the refund.

        payment_version_token : typing.Optional[str]
             Used for optimistic concurrency. This opaque token identifies the current `Payment`
            version that the caller expects. If the server has a different version of the Payment,
            the update fails and a response with a VERSION_MISMATCH error is returned.
            If the versions match, or the field is not provided, the refund proceeds as normal.

        team_member_id : typing.Optional[str]
            An optional [TeamMember](entity:TeamMember) ID to associate with this refund.

        cash_details : typing.Optional[DestinationDetailsCashRefundDetailsParams]
            Additional details required when recording an unlinked cash refund (`destination_id` is CASH).

        external_details : typing.Optional[DestinationDetailsExternalRefundDetailsParams]
            Additional details required when recording an unlinked external refund
            (`destination_id` is EXTERNAL).

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

        Returns
        -------
        HttpResponse[RefundPaymentResponse]
            Success
        """
        _response = self._client_wrapper.httpx_client.request(
            "v2/refunds",
            method="POST",
            json={
                "idempotency_key": idempotency_key,
                "amount_money": convert_and_respect_annotation_metadata(
                    object_=amount_money, annotation=MoneyParams, direction="write"
                ),
                "app_fee_money": convert_and_respect_annotation_metadata(
                    object_=app_fee_money, annotation=MoneyParams, direction="write"
                ),
                "payment_id": payment_id,
                "destination_id": destination_id,
                "unlinked": unlinked,
                "location_id": location_id,
                "customer_id": customer_id,
                "reason": reason,
                "payment_version_token": payment_version_token,
                "team_member_id": team_member_id,
                "cash_details": convert_and_respect_annotation_metadata(
                    object_=cash_details, annotation=DestinationDetailsCashRefundDetailsParams, direction="write"
                ),
                "external_details": convert_and_respect_annotation_metadata(
                    object_=external_details,
                    annotation=DestinationDetailsExternalRefundDetailsParams,
                    direction="write",
                ),
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    RefundPaymentResponse,
                    construct_type(
                        type_=RefundPaymentResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            _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(
        self, refund_id: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> HttpResponse[GetPaymentRefundResponse]:
        """
        Retrieves a specific refund using the `refund_id`.

        Parameters
        ----------
        refund_id : str
            The unique ID for the desired `PaymentRefund`.

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

        Returns
        -------
        HttpResponse[GetPaymentRefundResponse]
            Success
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v2/refunds/{jsonable_encoder(refund_id)}",
            method="GET",
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    GetPaymentRefundResponse,
                    construct_type(
                        type_=GetPaymentRefundResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            _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 AsyncRawRefundsClient:
    def __init__(self, *, client_wrapper: AsyncClientWrapper):
        self._client_wrapper = client_wrapper

    async def refund_payment(
        self,
        *,
        idempotency_key: str,
        amount_money: MoneyParams,
        app_fee_money: typing.Optional[MoneyParams] = OMIT,
        payment_id: typing.Optional[str] = OMIT,
        destination_id: typing.Optional[str] = OMIT,
        unlinked: typing.Optional[bool] = OMIT,
        location_id: typing.Optional[str] = OMIT,
        customer_id: typing.Optional[str] = OMIT,
        reason: typing.Optional[str] = OMIT,
        payment_version_token: typing.Optional[str] = OMIT,
        team_member_id: typing.Optional[str] = OMIT,
        cash_details: typing.Optional[DestinationDetailsCashRefundDetailsParams] = OMIT,
        external_details: typing.Optional[DestinationDetailsExternalRefundDetailsParams] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncHttpResponse[RefundPaymentResponse]:
        """
        Refunds a payment. You can refund the entire payment amount or a
        portion of it. You can use this endpoint to refund a card payment or record a
        refund of a cash or external payment. For more information, see
        [Refund Payment](https://developer.squareup.com/docs/payments-api/refund-payments).

        Parameters
        ----------
        idempotency_key : str
             A unique string that identifies this `RefundPayment` request. The key can be any valid string
            but must be unique for every `RefundPayment` request.

            Keys are limited to a max of 45 characters - however, the number of allowed characters might be
            less than 45, if multi-byte characters are used.

            For more information, see [Idempotency](https://developer.squareup.com/docs/working-with-apis/idempotency).

        amount_money : MoneyParams
            The amount of money to refund.

            This amount cannot be more than the `total_money` value of the payment minus the total
            amount of all previously completed refunds for this payment.

            This amount must be specified in the smallest denomination of the applicable currency
            (for example, US dollar amounts are specified in cents). For more information, see
            [Working with Monetary Amounts](https://developer.squareup.com/docs/build-basics/working-with-monetary-amounts).

            The currency code must match the currency associated with the business
            that is charging the card.

        app_fee_money : typing.Optional[MoneyParams]
            The amount of money the developer contributes to help cover the refunded amount.
            This amount is specified in the smallest denomination of the applicable currency (for example,
            US dollar amounts are specified in cents).

            The value cannot be more than the `amount_money`.

            You can specify this parameter in a refund request only if the same parameter was also included
            when taking the payment. This is part of the application fee scenario the API supports. For more
            information, see [Take Payments and Collect Fees](https://developer.squareup.com/docs/payments-api/take-payments-and-collect-fees).

            To set this field, `PAYMENTS_WRITE_ADDITIONAL_RECIPIENTS` OAuth permission is required.
            For more information, see [Permissions](https://developer.squareup.com/docs/payments-api/take-payments-and-collect-fees#permissions).

        payment_id : typing.Optional[str]
            The unique ID of the payment being refunded.
            Required when unlinked=false, otherwise must not be set.

        destination_id : typing.Optional[str]
            The ID indicating where funds will be refunded to. Required for unlinked refunds. For more
            information, see [Process an Unlinked Refund](https://developer.squareup.com/docs/refunds-api/unlinked-refunds).

            For refunds linked to Square payments, `destination_id` is usually omitted; in this case, funds
            will be returned to the original payment source. The field may be specified in order to request
            a cross-method refund to a gift card. For more information,
            see [Cross-method refunds to gift cards](https://developer.squareup.com/docs/payments-api/refund-payments#cross-method-refunds-to-gift-cards).

        unlinked : typing.Optional[bool]
            Indicates that the refund is not linked to a Square payment.
            If set to true, `destination_id` and `location_id` must be supplied while `payment_id` must not
            be provided.

        location_id : typing.Optional[str]
            The location ID associated with the unlinked refund.
            Required for requests specifying `unlinked=true`.
            Otherwise, if included when `unlinked=false`, will throw an error.

        customer_id : typing.Optional[str]
            The [Customer](entity:Customer) ID of the customer associated with the refund.
            This is required if the `destination_id` refers to a card on file created using the Cards
            API. Only allowed when `unlinked=true`.

        reason : typing.Optional[str]
            A description of the reason for the refund.

        payment_version_token : typing.Optional[str]
             Used for optimistic concurrency. This opaque token identifies the current `Payment`
            version that the caller expects. If the server has a different version of the Payment,
            the update fails and a response with a VERSION_MISMATCH error is returned.
            If the versions match, or the field is not provided, the refund proceeds as normal.

        team_member_id : typing.Optional[str]
            An optional [TeamMember](entity:TeamMember) ID to associate with this refund.

        cash_details : typing.Optional[DestinationDetailsCashRefundDetailsParams]
            Additional details required when recording an unlinked cash refund (`destination_id` is CASH).

        external_details : typing.Optional[DestinationDetailsExternalRefundDetailsParams]
            Additional details required when recording an unlinked external refund
            (`destination_id` is EXTERNAL).

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

        Returns
        -------
        AsyncHttpResponse[RefundPaymentResponse]
            Success
        """
        _response = await self._client_wrapper.httpx_client.request(
            "v2/refunds",
            method="POST",
            json={
                "idempotency_key": idempotency_key,
                "amount_money": convert_and_respect_annotation_metadata(
                    object_=amount_money, annotation=MoneyParams, direction="write"
                ),
                "app_fee_money": convert_and_respect_annotation_metadata(
                    object_=app_fee_money, annotation=MoneyParams, direction="write"
                ),
                "payment_id": payment_id,
                "destination_id": destination_id,
                "unlinked": unlinked,
                "location_id": location_id,
                "customer_id": customer_id,
                "reason": reason,
                "payment_version_token": payment_version_token,
                "team_member_id": team_member_id,
                "cash_details": convert_and_respect_annotation_metadata(
                    object_=cash_details, annotation=DestinationDetailsCashRefundDetailsParams, direction="write"
                ),
                "external_details": convert_and_respect_annotation_metadata(
                    object_=external_details,
                    annotation=DestinationDetailsExternalRefundDetailsParams,
                    direction="write",
                ),
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    RefundPaymentResponse,
                    construct_type(
                        type_=RefundPaymentResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            _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(
        self, refund_id: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> AsyncHttpResponse[GetPaymentRefundResponse]:
        """
        Retrieves a specific refund using the `refund_id`.

        Parameters
        ----------
        refund_id : str
            The unique ID for the desired `PaymentRefund`.

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

        Returns
        -------
        AsyncHttpResponse[GetPaymentRefundResponse]
            Success
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v2/refunds/{jsonable_encoder(refund_id)}",
            method="GET",
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    GetPaymentRefundResponse,
                    construct_type(
                        type_=GetPaymentRefundResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            _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)
