"""Portfolio container types."""

from __future__ import annotations

from dataclasses import dataclass, field
from decimal import Decimal

from fuggers_py.core.types import Currency

from .types import CashPosition, Holding, Position


@dataclass(frozen=True, slots=True)
class Portfolio:
    positions: tuple[Position | CashPosition, ...]
    currency: Currency

    @classmethod
    def new(cls, positions: list[Position | CashPosition], currency: Currency) -> "Portfolio":
        return cls(positions=tuple(positions), currency=currency)

    def total_quantity(self) -> Decimal:
        return sum((position.quantity for position in self.positions if hasattr(position, "quantity")), Decimal(0))

    def holdings(self) -> tuple[Position | CashPosition, ...]:
        return self.positions

    def investable_holdings(self) -> tuple[Holding, ...]:
        return tuple(position for position in self.positions if isinstance(position, Holding))

    def cash_positions(self) -> tuple[CashPosition, ...]:
        return tuple(position for position in self.positions if isinstance(position, CashPosition))

    def total_market_value(self) -> Decimal:
        total = Decimal(0)
        for position in self.positions:
            if isinstance(position, CashPosition):
                total += position.market_value()
            elif isinstance(position, Holding):
                total += position.market_value_amount
        return total


@dataclass(slots=True)
class PortfolioBuilder:
    currency: Currency | None = None
    _positions: list[Position | CashPosition] = field(default_factory=list)

    def with_currency(self, currency: Currency) -> "PortfolioBuilder":
        self.currency = currency
        return self

    def add_position(self, position: Position | CashPosition) -> "PortfolioBuilder":
        self._positions.append(position)
        if self.currency is None:
            currency = getattr(position, "currency", None)
            self.currency = currency() if callable(currency) else currency
        return self

    def add_holding(self, holding: Position | CashPosition) -> "PortfolioBuilder":
        return self.add_position(holding)

    def add_positions(self, positions: list[Position | CashPosition]) -> "PortfolioBuilder":
        for position in positions:
            self.add_position(position)
        return self

    def build(self) -> Portfolio:
        if self.currency is None:
            raise ValueError("PortfolioBuilder requires a currency.")
        return Portfolio.new(self._positions, currency=self.currency)


__all__ = ["Portfolio", "PortfolioBuilder"]
