"""Portfolio CRUD resource for TradePose Client.

This module provides operations for managing portfolios.
"""

import logging
from decimal import Decimal
from uuid import UUID

from pydantic import BaseModel, Field

from .base import BaseResource

logger = logging.getLogger(__name__)


# =============================================================================
# REQUEST/RESPONSE MODELS
# =============================================================================


class BlueprintSelectionResponse(BaseModel):
    """Blueprint selection in portfolio response."""

    strategy_id: UUID = Field(..., description="Strategy UUID")
    blueprint_id: UUID = Field(..., description="Blueprint UUID")
    strategy_name: str = Field(..., description="Strategy name")
    blueprint_name: str = Field(..., description="Blueprint name")


class PortfolioCreateRequest(BaseModel):
    """Portfolio creation request."""

    name: str = Field(..., description="Portfolio name")
    capital: Decimal = Field(..., description="Portfolio capital")
    currency: str = Field(..., description="Currency code (e.g., USD)")
    account_source: str = Field(..., description="Account source (e.g., BINANCE, FTMO)")
    blueprint_ids: list[UUID] = Field(
        default_factory=list, description="Blueprint UUIDs to allocate"
    )


class PortfolioUpdateRequest(BaseModel):
    """Portfolio update request."""

    capital: Decimal | None = Field(None, description="New capital")
    blueprint_ids: list[UUID] | None = Field(
        None, description="New blueprint UUIDs (replaces all allocations)"
    )


class PortfolioResponse(BaseModel):
    """Portfolio response model."""

    id: UUID
    name: str
    capital: Decimal
    currency: str
    account_source: str
    selections: list[BlueprintSelectionResponse]


class PortfolioListResponse(BaseModel):
    """Portfolio list response."""

    portfolios: list[PortfolioResponse]
    count: int


# =============================================================================
# RESOURCE CLASS
# =============================================================================


class PortfoliosResource(BaseResource):
    """Portfolio management resource.

    Provides operations for creating, reading, updating, and deleting portfolios.

    Example:
        >>> async with TradePoseClient(api_key="tp_live_xxx") as client:
        ...     # Create a portfolio with blueprint UUIDs
        ...     portfolio = await client.portfolios.create(
        ...         PortfolioCreateRequest(
        ...             name="Gold_Portfolio",
        ...             capital=Decimal("100000"),
        ...             currency="USD",
        ...             account_source="BINANCE",
        ...             blueprint_ids=[blueprint_uuid_1, blueprint_uuid_2],
        ...         )
        ...     )
        ...
        ...     # List all portfolios
        ...     portfolios = await client.portfolios.list()
    """

    async def create(self, request: PortfolioCreateRequest) -> PortfolioResponse:
        """Create a new portfolio.

        Args:
            request: Portfolio creation request

        Returns:
            Created portfolio

        Raises:
            ValidationError: If request data is invalid
            TradePoseAPIError: For other API errors
        """
        logger.info(f"Creating portfolio: {request.name}")

        response = await self._post("/api/v1/portfolios", json=request)

        result = PortfolioResponse(**response)
        logger.info(f"Created portfolio: {result.name}")
        return result

    async def list(self, *, archived: bool = False) -> PortfolioListResponse:
        """List all portfolios.

        Args:
            archived: Include archived portfolios

        Returns:
            List of portfolios

        Raises:
            TradePoseAPIError: For API errors
        """
        logger.debug(f"Listing portfolios (archived={archived})")

        params = {"archived": archived} if archived else None
        response = await self._get("/api/v1/portfolios", params=params)

        result = PortfolioListResponse(**response)
        logger.info(f"Listed {result.count} portfolios")
        return result

    async def get(self, name: str) -> PortfolioResponse:
        """Get portfolio by name.

        Args:
            name: Portfolio name

        Returns:
            Portfolio with selections

        Raises:
            ResourceNotFoundError: If portfolio not found
            TradePoseAPIError: For other API errors
        """
        logger.debug(f"Getting portfolio: {name}")

        response = await self._get(f"/api/v1/portfolios/{name}")

        result = PortfolioResponse(**response)
        logger.info(f"Retrieved portfolio: {result.name}")
        return result

    async def update(
        self,
        name: str,
        request: PortfolioUpdateRequest,
    ) -> PortfolioResponse:
        """Update a portfolio.

        Args:
            name: Portfolio name
            request: Update request

        Returns:
            Updated portfolio

        Raises:
            ResourceNotFoundError: If portfolio not found
            ValidationError: If update data is invalid
            TradePoseAPIError: For other API errors
        """
        logger.info(f"Updating portfolio: {name}")

        response = await self._put(f"/api/v1/portfolios/{name}", json=request)

        result = PortfolioResponse(**response)
        logger.info(f"Updated portfolio: {result.name}")
        return result

    async def delete(self, name: str, *, archive: bool = True) -> dict:
        """Delete or archive a portfolio.

        Args:
            name: Portfolio name
            archive: If True, soft delete (archive). If False, hard delete.

        Returns:
            Success message

        Raises:
            ResourceNotFoundError: If portfolio not found
            ValidationError: If portfolio has bindings (for hard delete)
            TradePoseAPIError: For other API errors
        """
        action = "Archiving" if archive else "Deleting"
        logger.info(f"{action} portfolio: {name}")

        params = {"archive": archive}
        response = await self._delete(f"/api/v1/portfolios/{name}", params=params)

        logger.info(f"Portfolio {name} {'archived' if archive else 'deleted'}")
        return response  # type: ignore
