"""Bond trait (`fuggers_py.bonds.traits.bond`)."""

from __future__ import annotations

from abc import ABC, abstractmethod
from decimal import Decimal

from fuggers_py.core.types import Currency, Date, Frequency

from ..types import BondIdentifiers, YieldCalculationRules
from .cashflow import BondCashFlow


class Bond(ABC):
    """Minimal bond interface used by pricing and cash-flow tooling.

    Implementations expose the contractual dates, notional, coupon schedule,
    and accrued-interest convention needed by the pricing and risk layers.
    """

    @abstractmethod
    def identifiers(self) -> BondIdentifiers:
        """Return instrument identifiers (ISIN/CUSIP/...)."""

    @abstractmethod
    def currency(self) -> Currency:
        """Return the bond currency."""

    @abstractmethod
    def notional(self) -> Decimal:
        """Return the bond notional used to scale cash flows."""

    @abstractmethod
    def issue_date(self) -> Date:
        """Return the issue/effective date."""

    @abstractmethod
    def maturity_date(self) -> Date:
        """Return maturity date."""

    @abstractmethod
    def frequency(self) -> Frequency:
        """Return coupon frequency."""

    @abstractmethod
    def rules(self) -> YieldCalculationRules:
        """Return yield calculation rules."""

    @abstractmethod
    def cash_flows(self, from_date: Date | None = None) -> list[BondCashFlow]:
        """Return cash flows sorted by date, optionally filtered from a date."""

    @abstractmethod
    def accrued_interest(self, settlement_date: Date) -> Decimal:
        """Return accrued interest in the bond's quoted price basis."""

    def max_date(self) -> Date:
        return self.maturity_date()

    def next_coupon_date(self, settlement_date: Date) -> Date | None:
        flows = [cf for cf in self.cash_flows() if cf.is_coupon()]
        for cf in flows:
            if cf.date > settlement_date:
                return cf.date
        return None

    def previous_coupon_date(self, settlement_date: Date) -> Date | None:
        flows = [cf for cf in self.cash_flows() if cf.is_coupon()]
        prev: Date | None = None
        for cf in flows:
            if cf.date <= settlement_date:
                prev = cf.date
            else:
                break
        return prev


__all__ = ["Bond"]
