"""Current yield helpers (`fuggers_py.analytics.yields.current`).

The public helpers return quoted percentage current yields. Inputs may be raw
decimals, percentage rates, coupon amounts, or bond-like objects depending on
the entry point.
"""

from __future__ import annotations

from decimal import Decimal
from typing import NoReturn

from fuggers_py.bonds.errors import BondPricingError
from fuggers_py.bonds.yields import (
    current_yield as _current_yield,
    current_yield_from_amount as _current_yield_from_amount,
    current_yield_from_bond as _current_yield_from_bond,
    current_yield_simple as _current_yield_simple,
)
from ..error import AnalyticsError


def _raise_invalid_input(exc: BondPricingError) -> NoReturn:
    raise AnalyticsError.invalid_input(exc.reason) from exc


def current_yield(coupon_rate: object, clean_price: object) -> Decimal:
    """Return current yield as a quoted percentage.

    Parameters
    ----------
    coupon_rate : object
        Annual coupon rate as a raw decimal or Decimal-like value.
    clean_price : object
        Clean price in percent of par.

    Returns
    -------
    Decimal
        Current yield quoted as percentage points, not a raw decimal rate.
    """

    try:
        return _current_yield(coupon_rate, clean_price)
    except BondPricingError as exc:
        _raise_invalid_input(exc)


def current_yield_from_amount(coupon_amount: object, clean_price: object) -> Decimal:
    """Return current yield as a quoted percentage.

    Parameters
    ----------
    coupon_amount : object
        Annual coupon payment in currency units per 100 face.
    clean_price : object
        Clean price in percent of par.

    Returns
    -------
    Decimal
        Current yield quoted as percentage points.
    """

    try:
        return _current_yield_from_amount(coupon_amount, clean_price)
    except BondPricingError as exc:
        _raise_invalid_input(exc)


def current_yield_from_bond(bond: object, clean_price: object) -> Decimal:
    """Return quoted current yield from a bond-like object.

    The bond must expose ``coupon_rate`` and ``notional`` either as methods or
    as attributes.
    """

    try:
        return _current_yield_from_bond(bond, clean_price)
    except BondPricingError as exc:
        _raise_invalid_input(exc)


def current_yield_simple(coupon_rate: float, clean_price: float) -> float:
    """Return current yield as a quoted percentage using float arithmetic."""

    try:
        return _current_yield_simple(coupon_rate, clean_price)
    except BondPricingError as exc:
        _raise_invalid_input(exc)


__all__ = [
    "current_yield",
    "current_yield_from_amount",
    "current_yield_from_bond",
    "current_yield_simple",
]
