"""Market making client for quote management."""

from __future__ import annotations

from decimal import Decimal
from typing import Any, Dict, List, Optional

from zenotc.clients.base import BaseClient
from zenotc.exceptions import QuoteNotFoundError
from zenotc.models.quote import Quote, QuoteRequest, QuoteStatus, QuoteUpdate
from zenotc.models.base import PaginatedResponse


class MarketMakingClient(BaseClient):
    """Client for market making operations."""

    async def submit_quote(
        self,
        asset: str,
        bid_price: float | Decimal,
        ask_price: float | Decimal,
        bid_size: float | Decimal,
        ask_size: float | Decimal,
        valid_for_seconds: int = 30,
        client_quote_id: Optional[str] = None,
        metadata: Optional[Dict[str, Any]] = None,
    ) -> Quote:
        """Submit a two-way quote."""
        request = QuoteRequest(
            asset=asset.upper(),
            bid_price=Decimal(str(bid_price)),
            ask_price=Decimal(str(ask_price)),
            bid_size=Decimal(str(bid_size)),
            ask_size=Decimal(str(ask_size)),
            valid_for_seconds=valid_for_seconds,
            client_quote_id=client_quote_id,
            metadata=metadata,
        )

        await self._rate_limiter.acquire()
        response = await self._http.post("/api/v1/quotes", json_data=request)
        return Quote.model_validate(response)

    async def update_quote(
        self,
        quote_id: str,
        bid_price: Optional[float | Decimal] = None,
        ask_price: Optional[float | Decimal] = None,
        bid_size: Optional[float | Decimal] = None,
        ask_size: Optional[float | Decimal] = None,
        valid_for_seconds: Optional[int] = None,
    ) -> Quote:
        """Update an existing quote."""
        update = QuoteUpdate(
            bid_price=Decimal(str(bid_price)) if bid_price is not None else None,
            ask_price=Decimal(str(ask_price)) if ask_price is not None else None,
            bid_size=Decimal(str(bid_size)) if bid_size is not None else None,
            ask_size=Decimal(str(ask_size)) if ask_size is not None else None,
            valid_for_seconds=valid_for_seconds,
        )

        await self._rate_limiter.acquire()
        try:
            response = await self._http.patch(f"/api/v1/quotes/{quote_id}", json_data=update)
            return Quote.model_validate(response)
        except Exception as e:
            if hasattr(e, "status_code") and e.status_code == 404:
                raise QuoteNotFoundError(quote_id) from e
            raise

    async def cancel_quote(self, quote_id: str) -> Quote:
        """Cancel a quote."""
        await self._rate_limiter.acquire()
        try:
            response = await self._http.delete(f"/api/v1/quotes/{quote_id}")
            return Quote.model_validate(response)
        except Exception as e:
            if hasattr(e, "status_code") and e.status_code == 404:
                raise QuoteNotFoundError(quote_id) from e
            raise

    async def cancel_all_quotes(self, asset: Optional[str] = None) -> int:
        """Cancel all active quotes.

        Args:
            asset: Optional asset to filter quotes by

        Returns:
            Number of quotes cancelled
        """
        body: Dict[str, Any] = {}
        if asset:
            body["asset"] = asset.upper()

        await self._rate_limiter.acquire()
        response = await self._http.delete("/api/v1/quotes", json_data=body if body else None)
        return response.get("cancelledCount", 0)

    async def get_quote(self, quote_id: str) -> Quote:
        """Get quote by ID."""
        await self._rate_limiter.acquire()
        try:
            response = await self._http.get(f"/api/v1/quotes/{quote_id}")
            return Quote.model_validate(response)
        except Exception as e:
            if hasattr(e, "status_code") and e.status_code == 404:
                raise QuoteNotFoundError(quote_id) from e
            raise

    async def get_quotes(
        self,
        status: Optional[str | List[str]] = None,
        asset: Optional[str] = None,
        page: int = 1,
        limit: int = 50,
    ) -> PaginatedResponse[Quote]:
        """Get quotes with filtering and pagination."""
        params: Dict[str, Any] = {"page": page, "limit": limit}

        if status:
            if isinstance(status, list):
                params["statuses"] = ",".join(status)
            else:
                params["statuses"] = status
        if asset:
            params["asset"] = asset.upper()

        await self._rate_limiter.acquire()
        response = await self._http.get("/api/v1/quotes", params=params)

        quotes = [Quote.model_validate(q) for q in response.get("data", [])]
        return PaginatedResponse[Quote](
            data=quotes,
            total=response.get("total", len(quotes)),
            page=response.get("page", page),
            limit=response.get("limit", limit),
            has_more=response.get("hasMore", False),
        )

    async def get_active_quotes(self, asset: Optional[str] = None) -> List[Quote]:
        """Get all active quotes."""
        result = await self.get_quotes(
            status=[QuoteStatus.ACTIVE.value, QuoteStatus.PARTIALLY_FILLED.value],
            asset=asset,
            limit=100,
        )
        return result.data

    async def refresh_quote(self, quote_id: str, valid_for_seconds: int = 30) -> Quote:
        """Refresh a quote's expiration time."""
        return await self.update_quote(quote_id, valid_for_seconds=valid_for_seconds)

    async def get_quote_fills(
        self, quote_id: str, page: int = 1, limit: int = 50
    ) -> Dict[str, Any]:
        """Get fills for a specific quote."""
        params = {"page": page, "limit": limit}
        await self._rate_limiter.acquire()
        response = await self._http.get(f"/api/v1/quotes/{quote_id}/fills", params=params)
        return response
