"""Synchronous wrappers for OxaPay async API client."""

import asyncio
import types
from collections.abc import Callable
from functools import wraps
from typing import TypeVar

from .client import OxaPayClient
from .models.balance import AccountBalanceResponse
from .models.exchange import (
    SwapCalculateRequest,
    SwapCalculateResponse,
    SwapHistoryRequest,
    SwapHistoryResponse,
    SwapPairsResponse,
    SwapRateRequest,
    SwapRateResponse,
    SwapRequest,
    SwapResponse,
)
from .models.merchant import (
    AcceptedCoinsResponse,
    CreateInvoiceRequest,
    CreateInvoiceResponse,
    CreateStaticWalletRequest,
    CreateStaticWalletResponse,
    CreateWhiteLabelRequest,
    CreateWhiteLabelResponse,
    PaymentHistoryRequest,
    PaymentHistoryResponse,
    PaymentInfoResponse,
    RevokeStaticWalletRequest,
    RevokeStaticWalletResponse,
    StaticWalletListRequest,
    StaticWalletListResponse,
)
from .models.payout import (
    CreatePayoutRequest,
    CreatePayoutResponse,
    PayoutHistoryRequest,
    PayoutHistoryResponse,
    PayoutInfoResponse,
)
from .models.system import (
    NetworksResponse,
    PriceResponse,
    SupportedCurrenciesResponse,
    SupportedFiatsResponse,
)

T = TypeVar("T")


def sync_wrapper(func: Callable[..., T]) -> Callable[..., T]:
    """Convert an async function to a sync function.

    Args:
        func: The async function to convert

    Returns:
        A synchronous wrapper that runs the async function in an event loop

    """

    @wraps(func)
    def wrapper(*args: object, **kwargs: object) -> T:
        try:
            loop = asyncio.get_event_loop()
        except RuntimeError:
            # If there's no event loop in the current thread, create one
            loop = asyncio.new_event_loop()
            asyncio.set_event_loop(loop)

        return loop.run_until_complete(func(*args, **kwargs))

    return wrapper


class SyncOxaPayClient:
    """Synchronous wrapper for OxaPayClient.

    Provides the same methods as OxaPayClient but in a synchronous manner.
    """

    def __init__(
        self,
        merchant_api_key: str | None = None,
        payout_api_key: str | None = None,
        general_api_key: str | None = None,
    ) -> None:
        """Initialize the sync OxaPay client.

        Args:
            merchant_api_key: API key for merchant operations
            payout_api_key: API key for payout operations
            general_api_key: API key for general operations like exchange

        """
        self._async_client = OxaPayClient(
            merchant_api_key=merchant_api_key,
            payout_api_key=payout_api_key,
            general_api_key=general_api_key,
        )

    def __enter__(self) -> "SyncOxaPayClient":
        """Enter context manager.

        Returns:
            The SyncOxaPayClient instance

        """
        return self

    def __exit__(
        self,
        exc_type: type[BaseException] | None,
        exc_val: BaseException | None,
        exc_tb: types.TracebackType | None,
    ) -> None:
        """Exit context manager.

        Args:
            exc_type: Exception type if an exception was raised
            exc_val: Exception value if an exception was raised
            exc_tb: Exception traceback if an exception was raised

        """

    # Merchant API Methods

    @sync_wrapper
    def create_invoice(
        self,
        request: CreateInvoiceRequest,
    ) -> CreateInvoiceResponse:
        """Create a new payment invoice.

        Args:
            request: Invoice creation parameters

        Returns:
            Invoice creation response

        """
        return self._async_client.create_invoice(request)

    @sync_wrapper
    def create_white_label(
        self,
        request: CreateWhiteLabelRequest,
    ) -> CreateWhiteLabelResponse:
        """Create a white-label payment.

        Args:
            request: White-label payment request parameters

        Returns:
            White-label payment response

        """
        return self._async_client.create_white_label(request)

    @sync_wrapper
    def create_static_wallet(
        self,
        request: CreateStaticWalletRequest,
    ) -> CreateStaticWalletResponse:
        """Create a static wallet address.

        Args:
            request: Static wallet creation parameters

        Returns:
            Static wallet creation response

        """
        return self._async_client.create_static_wallet(request)

    @sync_wrapper
    def revoke_static_wallet(
        self,
        request: RevokeStaticWalletRequest,
    ) -> RevokeStaticWalletResponse:
        """Revoke a static wallet address.

        Args:
            request: Revocation parameters

        Returns:
            Revocation response

        """
        return self._async_client.revoke_static_wallet(request)

    @sync_wrapper
    def get_static_wallets(
        self,
        request: StaticWalletListRequest,
    ) -> StaticWalletListResponse:
        """List static wallets.

        Args:
            request: List filter parameters

        Returns:
            List of static wallets

        """
        return self._async_client.get_static_wallets(request)

    @sync_wrapper
    def get_payment_info(self, track_id: str | int) -> PaymentInfoResponse:
        """Get information about a specific payment.

        Args:
            track_id: The payment tracking ID

        Returns:
            Payment information

        """
        return self._async_client.get_payment_info(track_id)

    @sync_wrapper
    def get_payment_history(
        self,
        request: PaymentHistoryRequest,
    ) -> PaymentHistoryResponse:
        """Get payment history.

        Args:
            request: History filter parameters

        Returns:
            Payment history

        """
        return self._async_client.get_payment_history(request)

    @sync_wrapper
    def get_accepted_coins(self) -> AcceptedCoinsResponse:
        """Get accepted coins.

        Returns:
            List of accepted coins

        """
        return self._async_client.get_accepted_coins()

    # Payout API Methods

    @sync_wrapper
    def create_payout(self, request: CreatePayoutRequest) -> CreatePayoutResponse:
        """Create a new payout.

        Args:
            request: Payout creation parameters

        Returns:
            Payout creation response with tracking ID

        """
        return self._async_client.create_payout(request)

    @sync_wrapper
    def get_payout_info(self, track_id: str | int) -> PayoutInfoResponse:
        """Get information about a specific payout.

        Args:
            track_id: The payout tracking ID

        Returns:
            Payout information

        """
        return self._async_client.get_payout_info(track_id)

    @sync_wrapper
    def get_payout_history(
        self,
        request: PayoutHistoryRequest,
    ) -> PayoutHistoryResponse:
        """Get payout history.

        Args:
            request: Payout history request parameters

        Returns:
            Payout history with pagination info

        """
        return self._async_client.get_payout_history(request)

    @sync_wrapper
    def get_payout_balance(self, currency: str | None = None) -> AccountBalanceResponse:
        """Get payout account balance.

        Args:
            currency: Specific currency to get balance for (optional)

        Returns:
            Account balance information

        """
        return self._async_client.get_payout_balance(currency)

    # General/Swap API Methods

    @sync_wrapper
    def get_account_balance(
        self,
        currency: str | None = None,
    ) -> AccountBalanceResponse:
        """Get general account balance.

        Args:
            currency: Specific currency to get balance for (optional)

        Returns:
            Account balance information

        """
        return self._async_client.get_account_balance(currency)

    @sync_wrapper
    def get_swap_rate(
        self,
        request: SwapRateRequest,
    ) -> SwapRateResponse:
        """Get swap rate between two currencies.

        Args:
            request: Swap rate request parameters

        Returns:
            Swap rate information

        """
        return self._async_client.get_swap_rate(request)

    @sync_wrapper
    def calculate_swap(
        self,
        request: SwapCalculateRequest,
    ) -> SwapCalculateResponse:
        """Calculate swap amount.

        Args:
            request: Swap calculation request parameters

        Returns:
            Swap calculation result

        """
        return self._async_client.calculate_swap(request)

    @sync_wrapper
    def get_swap_pairs(self) -> SwapPairsResponse:
        """Get available swap pairs.

        Returns:
            List of available swap pairs

        """
        return self._async_client.get_swap_pairs()

    @sync_wrapper
    def create_swap_request(
        self,
        request: SwapRequest,
    ) -> SwapResponse:
        """Create a new swap request.

        Args:
            request: Swap request parameters

        Returns:
            Swap request creation response

        """
        return self._async_client.create_swap_request(request)

    @sync_wrapper
    def get_swap_history(
        self,
        request: SwapHistoryRequest,
    ) -> SwapHistoryResponse:
        """Get swap history.

        Args:
            request: Swap history request parameters

        Returns:
            Swap history with pagination info

        """
        return self._async_client.get_swap_history(request)

    # System/Common API Methods

    @sync_wrapper
    def get_prices(self) -> PriceResponse:
        """Get current prices of all supported cryptocurrencies.

        Returns:
            Current prices information

        """
        return self._async_client.get_prices()

    @sync_wrapper
    def get_supported_currencies(self) -> SupportedCurrenciesResponse:
        """Get a list of supported currencies.

        Returns:
            List of supported currencies with network details

        """
        return self._async_client.get_supported_currencies()

    @sync_wrapper
    def get_supported_fiats(self) -> SupportedFiatsResponse:
        """Get a list of supported fiat currencies.

        Returns:
            List of supported fiat currencies

        """
        return self._async_client.get_supported_fiats()

    @sync_wrapper
    def get_networks(self) -> NetworksResponse:
        """Get a list of supported blockchain networks.

        Returns:
            List of supported networks

        """
        return self._async_client.get_networks()

    @sync_wrapper
    def check_system_status(self) -> str:
        """Check if the OxaPay API is operational.

        Returns:
            Status message (usually "OK")

        """
        return self._async_client.check_system_status()

    def verify_webhook_signature(
        self,
        signature: str,
        payload: str,
        *,
        is_payment: bool = True,
    ) -> bool:
        """Verify the HMAC signature of a webhook payload.

        Args:
            signature: The HMAC signature from the webhook header
            payload: The raw webhook payload
            is_payment: Whether this is a payment webhook (True) or payout webhook (False)

        Returns:
            True if the signature is valid, False otherwise

        """  # noqa: E501
        return self._async_client.verify_webhook_signature(
            signature,
            payload,
            is_payment=is_payment,
        )
