"""
Payback period.

Linear interpolation within the crossing year: returns the moment when the
running net cashflow first turns non-negative.

Inputs are *risk-adjusted, undiscounted* cashflows by convention (TEI shows
"<6 months" payback for the Amazon Connect composite using the risk-adjusted
nominal cashflows from the Cash Flow Analysis table).
"""

from __future__ import annotations

from collections.abc import Iterable


def payback_years(
    initial_cost: float,
    yearly_net_benefits: Iterable[float],
) -> float | None:
    """
    Years until cumulative net benefits cover the initial cost.

    Args:
        initial_cost: positive number — undiscounted year-0 outlay.
        yearly_net_benefits: sequence of (benefits − costs) per year, Y1+.

    Returns:
        Float number of years, or ``None`` if payback is never reached
        within the supplied horizon.

    Example::

        >>> # Amazon Connect: initial cost $1.196M, Y1 net $19.998M
        >>> # → ~0.06 years ≈ 0.7 months — well under 6 months.
        >>> round(payback_years(1_196_250, [19_997_953, 31_562_489, 47_443_905]), 3)
        0.06
    """
    remaining = float(initial_cost)
    if remaining <= 0:
        return 0.0
    cumulative_year = 0
    for cf in yearly_net_benefits:
        cumulative_year += 1
        cf = float(cf)
        if cf <= 0:
            remaining += -cf  # net loss this year increases the gap
            continue
        if cf >= remaining:
            # Crossing happens partway through this year.
            fraction = remaining / cf
            return (cumulative_year - 1) + fraction
        remaining -= cf
    return None


def payback_months(
    initial_cost: float,
    yearly_net_benefits: Iterable[float],
) -> float | None:
    """Same as :func:`payback_years`, expressed in months."""
    yrs = payback_years(initial_cost, yearly_net_benefits)
    return yrs * 12.0 if yrs is not None else None
