"""Refunds resource."""

from typing import Any, AsyncIterator, Dict, Iterator, Optional

from ..client import AsyncHttpClient, HttpClient
from ..pagination import PaginatedResponse, async_paginate, paginate
from ..types import RefundResponseDto

BASE_PATH = "/api/v1/refunds"


class RefundsResource:
    """Synchronous refunds resource.

    Wraps endpoints under ``/api/v1/refunds``.
    """

    def __init__(self, client: HttpClient) -> None:
        self._client = client

    def create_for_session(
        self,
        session_reference: str,
        *,
        refund_address: str,
        reason: Optional[str] = None,
        fee_paid_by: Optional[str] = None,
    ) -> RefundResponseDto:
        """Create a refund for a payment session.

        Args:
            session_reference: The session reference to refund.
            refund_address: Customer wallet address to receive the refund.
            reason: Reason for the refund. Optional.
            fee_paid_by: "merchant" or "customer". Optional.

        Returns:
            The created refund object.
        """
        body: Dict[str, Any] = {
            "refundAddress": refund_address,
        }
        if reason is not None:
            body["reason"] = reason
        if fee_paid_by is not None:
            body["feePaidBy"] = fee_paid_by

        return self._client.request(
            "POST",
            f"{BASE_PATH}/session/{session_reference}",
            json_body=body,
        )

    def create_for_invoice(
        self,
        invoice_reference: str,
        *,
        refund_address: str,
        reason: Optional[str] = None,
        fee_paid_by: Optional[str] = None,
    ) -> RefundResponseDto:
        """Create a refund for an invoice.

        Args:
            invoice_reference: The invoice reference to refund.
            refund_address: Customer wallet address to receive the refund.
            reason: Reason for the refund. Optional.
            fee_paid_by: "merchant" or "customer". Optional.

        Returns:
            The created refund object.
        """
        body: Dict[str, Any] = {
            "refundAddress": refund_address,
        }
        if reason is not None:
            body["reason"] = reason
        if fee_paid_by is not None:
            body["feePaidBy"] = fee_paid_by

        return self._client.request(
            "POST",
            f"{BASE_PATH}/invoice/{invoice_reference}",
            json_body=body,
        )

    def list(
        self,
        *,
        page: int = 1,
        size: int = 10,
        status: Optional[str] = None,
        session_reference: Optional[str] = None,
        invoice_reference: Optional[str] = None,
        search: Optional[str] = None,
        start_date: Optional[str] = None,
        end_date: Optional[str] = None,
    ) -> PaginatedResponse:
        """List refunds with pagination.

        Returns:
            A PaginatedResponse containing RefundResponseDto items.
        """
        params: Dict[str, Any] = {
            "page": page,
            "size": size,
            "status": status,
            "sessionReference": session_reference,
            "invoiceReference": invoice_reference,
            "search": search,
            "startDate": start_date,
            "endDate": end_date,
        }
        return self._client.request_paginated("GET", BASE_PATH, params=params)

    def list_auto_paginate(self, **kwargs: Any) -> Iterator[RefundResponseDto]:
        """Iterate over all refunds across all pages."""
        return paginate(self.list, params=kwargs)

    def get(self, refund_id: str) -> RefundResponseDto:
        """Get a refund by ID.

        Args:
            refund_id: The refund UUID.

        Returns:
            The refund object.
        """
        return self._client.request("GET", f"{BASE_PATH}/{refund_id}")

    def estimate(
        self,
        reference: str,
        *,
        entity: Optional[str] = None,
        fee_paid_by: Optional[str] = None,
    ) -> Dict[str, Any]:
        """Estimate a refund for a session or invoice.

        Args:
            reference: The session or invoice reference.
            entity: Entity type ("session" or "invoice"). Optional.
            fee_paid_by: "merchant" or "customer". Optional.

        Returns:
            Refund estimate data.
        """
        params: Dict[str, Any] = {
            "entity": entity,
            "feePaidBy": fee_paid_by,
        }
        return self._client.request(
            "GET",
            f"{BASE_PATH}/estimate/{reference}",
            params=params,
        )


class AsyncRefundsResource:
    """Asynchronous refunds resource."""

    def __init__(self, client: AsyncHttpClient) -> None:
        self._client = client

    async def create_for_session(
        self,
        session_reference: str,
        *,
        refund_address: str,
        reason: Optional[str] = None,
        fee_paid_by: Optional[str] = None,
    ) -> RefundResponseDto:
        """Create a refund for a payment session (async)."""
        body: Dict[str, Any] = {
            "refundAddress": refund_address,
        }
        if reason is not None:
            body["reason"] = reason
        if fee_paid_by is not None:
            body["feePaidBy"] = fee_paid_by

        return await self._client.request(
            "POST",
            f"{BASE_PATH}/session/{session_reference}",
            json_body=body,
        )

    async def create_for_invoice(
        self,
        invoice_reference: str,
        *,
        refund_address: str,
        reason: Optional[str] = None,
        fee_paid_by: Optional[str] = None,
    ) -> RefundResponseDto:
        """Create a refund for an invoice (async)."""
        body: Dict[str, Any] = {
            "refundAddress": refund_address,
        }
        if reason is not None:
            body["reason"] = reason
        if fee_paid_by is not None:
            body["feePaidBy"] = fee_paid_by

        return await self._client.request(
            "POST",
            f"{BASE_PATH}/invoice/{invoice_reference}",
            json_body=body,
        )

    async def list(
        self,
        *,
        page: int = 1,
        size: int = 10,
        status: Optional[str] = None,
        session_reference: Optional[str] = None,
        invoice_reference: Optional[str] = None,
        search: Optional[str] = None,
        start_date: Optional[str] = None,
        end_date: Optional[str] = None,
    ) -> PaginatedResponse:
        """List refunds with pagination (async)."""
        params: Dict[str, Any] = {
            "page": page,
            "size": size,
            "status": status,
            "sessionReference": session_reference,
            "invoiceReference": invoice_reference,
            "search": search,
            "startDate": start_date,
            "endDate": end_date,
        }
        return await self._client.request_paginated("GET", BASE_PATH, params=params)

    def list_auto_paginate(self, **kwargs: Any) -> AsyncIterator[RefundResponseDto]:
        """Iterate over all refunds across all pages (async)."""
        return async_paginate(self.list, params=kwargs)

    async def get(self, refund_id: str) -> RefundResponseDto:
        """Get a refund by ID (async)."""
        return await self._client.request("GET", f"{BASE_PATH}/{refund_id}")

    async def estimate(
        self,
        reference: str,
        *,
        entity: Optional[str] = None,
        fee_paid_by: Optional[str] = None,
    ) -> Dict[str, Any]:
        """Estimate a refund for a session or invoice (async)."""
        params: Dict[str, Any] = {
            "entity": entity,
            "feePaidBy": fee_paid_by,
        }
        return await self._client.request(
            "GET",
            f"{BASE_PATH}/estimate/{reference}",
            params=params,
        )
