"""
Aggregated Merchants API resource.

Endpoints:
    GET    /v1/aggregated_merchants
    POST   /v1/aggregated_merchants
    GET    /v1/aggregated_merchants/:id
    PUT    /v1/aggregated_merchants/:id
    DELETE /v1/aggregated_merchants/:id
"""

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

from .session import WaveSession


class AggregatedMerchantsAPI:
    """
    Interact with the Wave Aggregated Merchants API.

    Create, update, retrieve, list, and delete aggregated merchant identities
    for use with the Checkout and Payout APIs.

    .. note::
        Access to this API is limited to selected Wave partners who operate
        as aggregators. Contact your Wave representative to request access.
    """

    def __init__(self, session: WaveSession):
        self._session = session

    def list(
        self,
        first: Optional[int] = None,
        after: Optional[str] = None,
    ) -> Dict[str, Any]:
        """
        Retrieve a paginated list of aggregated merchants.

        Args:
            first: Maximum number of items per page.
            after: Cursor for the next page (value of end_cursor from previous response).

        Returns:
            Paginated response::

                {
                    "page_info": {"has_next_page": false, "end_cursor": "..."},
                    "items": [...]
                }

        Example::

            result = client.aggregated_merchants.list(first=10)
            for merchant in result["items"]:
                print(merchant["id"], merchant["name"])
        """
        params: Dict[str, Any] = {}
        if first is not None:
            params["first"] = first
        if after:
            params["after"] = after
        return self._session.get("/v1/aggregated_merchants", params=params or None)

    def list_all(self) -> Iterator[Dict[str, Any]]:
        """
        Retrieve ALL aggregated merchants, automatically handling pagination.

        Yields:
            Individual aggregated merchant dicts.

        Example::

            for merchant in client.aggregated_merchants.list_all():
                print(merchant["name"])
        """
        cursor = None
        while True:
            response = self.list(after=cursor)
            yield from response.get("items", [])
            page_info = response.get("page_info", {})
            if not page_info.get("has_next_page"):
                break
            cursor = page_info.get("end_cursor")

    def create(
        self,
        name: str,
        business_type: str,
        business_description: str,
        business_sector: Optional[str] = None,
        business_registration_identifier: Optional[str] = None,
        website_url: Optional[str] = None,
        manager_name: Optional[str] = None,
    ) -> Dict[str, Any]:
        """
        Create a new aggregated merchant identity.

        Args:
            name: Unique name for this merchant (required, max 255 chars).
            business_type: Either "fintech" or "other" (required).
            business_description: Description of the business (required).
            business_sector: Free-form text for the sector (e.g., "agriculture").
            business_registration_identifier: Business registration number.
            website_url: Business website URL (max 2083 chars).
            manager_name: Name of the business manager.

        Returns:
            Created Aggregated Merchant object.

        Raises:
            WaveValidationError: If required fields are missing or invalid.
            WaveAPIError: If a merchant with the same name already exists.

        Example::

            merchant = client.aggregated_merchants.create(
                name="Fatou's Market",
                business_type="other",
                business_description="A local market in Dakar.",
                business_sector="retail",
                manager_name="Fatou Diallo",
            )
            print(merchant["id"])  # am-...
        """
        payload: Dict[str, Any] = {
            "name": name,
            "business_type": business_type,
            "business_description": business_description,
        }
        if business_sector is not None:
            payload["business_sector"] = business_sector
        if business_registration_identifier is not None:
            payload["business_registration_identifier"] = business_registration_identifier
        if website_url is not None:
            payload["website_url"] = website_url
        if manager_name is not None:
            payload["manager_name"] = manager_name

        return self._session.post("/v1/aggregated_merchants", json=payload)

    def get(self, merchant_id: str) -> Dict[str, Any]:
        """
        Retrieve a single aggregated merchant by ID.

        Args:
            merchant_id: Aggregated merchant ID (starts with 'am-').

        Returns:
            Aggregated Merchant object.

        Raises:
            WaveNotFoundError: If the merchant does not exist.

        Example::

            merchant = client.aggregated_merchants.get("am-7lks22ap113t4")
            print(merchant["name"], merchant["is_locked"])
        """
        return self._session.get(f"/v1/aggregated_merchants/{merchant_id}")

    def update(
        self,
        merchant_id: str,
        name: str,
        business_type: str,
        business_description: str,
        business_sector: Optional[str] = None,
        business_registration_identifier: Optional[str] = None,
        website_url: Optional[str] = None,
        manager_name: Optional[str] = None,
    ) -> Dict[str, Any]:
        """
        Update an aggregated merchant's details.

        .. note::
            Once Wave has reviewed and locked a merchant, updates will fail
            with a 403 Forbidden error. You can still delete locked merchants.

        Args:
            merchant_id: Aggregated merchant ID (starts with 'am-').
            name: New name for the merchant.
            business_type: Either "fintech" or "other".
            business_description: Updated description.
            business_sector: Updated sector text.
            business_registration_identifier: Updated registration number.
            website_url: Updated website URL.
            manager_name: Updated manager name.

        Returns:
            Updated Aggregated Merchant object.

        Raises:
            WaveNotFoundError: If the merchant does not exist.
            WaveAuthError: If the merchant is locked.

        Example::

            updated = client.aggregated_merchants.update(
                merchant_id="am-7lks22ap113t4",
                name="Fatou's Super Market",
                business_type="other",
                business_description="An expanded market.",
            )
        """
        payload: Dict[str, Any] = {
            "name": name,
            "business_type": business_type,
            "business_description": business_description,
        }
        if business_sector is not None:
            payload["business_sector"] = business_sector
        if business_registration_identifier is not None:
            payload["business_registration_identifier"] = business_registration_identifier
        if website_url is not None:
            payload["website_url"] = website_url
        if manager_name is not None:
            payload["manager_name"] = manager_name

        return self._session.put(f"/v1/aggregated_merchants/{merchant_id}", json=payload)

    def delete(self, merchant_id: str) -> None:
        """
        Delete an aggregated merchant.

        The merchant will no longer be usable after deletion.
        This works even for locked merchants.

        Args:
            merchant_id: Aggregated merchant ID (starts with 'am-').

        Returns:
            None on success.

        Raises:
            WaveNotFoundError: If the merchant does not exist.

        Example::

            client.aggregated_merchants.delete("am-7lks22ap113t4")
        """
        return self._session.delete(f"/v1/aggregated_merchants/{merchant_id}")
