"""Portfolio models for ZenOTC SDK."""

from __future__ import annotations

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

from pydantic import Field

from zenotc.models.base import BaseModel, TimestampMixin


class Balance(BaseModel):
    """Asset balance."""

    asset: str = Field(..., description="Asset symbol")
    total: Decimal = Field(..., description="Total balance")
    available: Decimal = Field(..., description="Available balance (not locked)")
    locked: Decimal = Field(default=Decimal("0"), description="Locked balance (in orders/escrow)")
    pending_deposit: Decimal = Field(
        default=Decimal("0"), description="Pending deposit amount"
    )
    pending_withdrawal: Decimal = Field(
        default=Decimal("0"), description="Pending withdrawal amount"
    )
    updated_at: datetime = Field(..., description="Last update timestamp")

    @property
    def effective_available(self) -> Decimal:
        """Get effective available balance including pending deposits."""
        return self.available + self.pending_deposit


class Position(BaseModel):
    """Trading position."""

    asset: str = Field(..., description="Asset symbol")
    quantity: Decimal = Field(..., description="Position quantity")
    average_entry_price: Decimal = Field(..., description="Average entry price")
    current_price: Decimal = Field(..., description="Current market price")
    market_value: Decimal = Field(..., description="Current market value")
    unrealized_pnl: Decimal = Field(..., description="Unrealized P&L")
    unrealized_pnl_percentage: float = Field(..., description="Unrealized P&L percentage")
    cost_basis: Decimal = Field(..., description="Total cost basis")
    updated_at: datetime = Field(..., description="Last update timestamp")

    @property
    def is_long(self) -> bool:
        """Check if position is long."""
        return self.quantity > 0

    @property
    def is_short(self) -> bool:
        """Check if position is short."""
        return self.quantity < 0


class Exposure(BaseModel):
    """Exposure for a single asset."""

    asset: str = Field(..., description="Asset symbol")
    notional_value: Decimal = Field(..., description="Notional exposure value")
    percentage_of_portfolio: float = Field(..., description="Percentage of total portfolio")
    long_exposure: Decimal = Field(default=Decimal("0"), description="Long exposure")
    short_exposure: Decimal = Field(default=Decimal("0"), description="Short exposure")
    net_exposure: Decimal = Field(..., description="Net exposure")


class ExposureSummary(BaseModel):
    """Portfolio exposure summary."""

    total_notional: Decimal = Field(..., description="Total notional value")
    total_long_exposure: Decimal = Field(..., description="Total long exposure")
    total_short_exposure: Decimal = Field(..., description="Total short exposure")
    net_exposure: Decimal = Field(..., description="Net exposure")
    gross_exposure: Decimal = Field(..., description="Gross exposure")
    exposures_by_asset: List[Exposure] = Field(..., description="Exposures by asset")
    updated_at: datetime = Field(..., description="Last update timestamp")

    @property
    def leverage(self) -> float:
        """Calculate leverage ratio."""
        if self.total_notional == 0:
            return 0.0
        return float(self.gross_exposure / self.total_notional)


class PortfolioSummary(BaseModel):
    """Complete portfolio summary."""

    total_value: Decimal = Field(..., description="Total portfolio value in base currency")
    total_value_currency: str = Field(default="USD", description="Base currency")
    total_pnl: Decimal = Field(..., description="Total P&L")
    total_pnl_percentage: float = Field(..., description="Total P&L percentage")
    daily_pnl: Decimal = Field(..., description="Daily P&L")
    daily_pnl_percentage: float = Field(..., description="Daily P&L percentage")
    balances: List[Balance] = Field(..., description="All asset balances")
    positions: List[Position] = Field(..., description="All positions")
    exposure: ExposureSummary = Field(..., description="Exposure summary")
    open_orders_count: int = Field(..., description="Number of open orders")
    active_trades_count: int = Field(..., description="Number of active trades")
    updated_at: datetime = Field(..., description="Last update timestamp")

    def get_balance(self, asset: str) -> Optional[Balance]:
        """Get balance for a specific asset."""
        for balance in self.balances:
            if balance.asset == asset:
                return balance
        return None

    def get_position(self, asset: str) -> Optional[Position]:
        """Get position for a specific asset."""
        for position in self.positions:
            if position.asset == asset:
                return position
        return None

    def to_dict_by_asset(self) -> Dict[str, Balance]:
        """Get balances as dictionary keyed by asset."""
        return {b.asset: b for b in self.balances}
