"""G-spread helpers.

All public spread values in this module are returned in basis points. Benchmark
yields remain raw decimals and are only converted to bps at the spread layer.
"""

from __future__ import annotations

from dataclasses import dataclass
from decimal import Decimal

from fuggers_py.bonds.traits import Bond
from fuggers_py.bonds.types import Tenor
from fuggers_py.core.types import Date

from .benchmark import BenchmarkSpec, BenchmarkKind, _to_decimal
from .government_curve import GovernmentCurve


def g_spread(bond_yield: object, benchmark_yield: object) -> Decimal:
    """Return the g-spread in basis points."""
    by = _to_decimal(bond_yield)
    gy = _to_decimal(benchmark_yield)
    return (by - gy) * Decimal(10_000)


def g_spread_with_benchmark(
    bond_yield: object,
    curve: GovernmentCurve,
    maturity: Tenor | Date,
    *,
    benchmark: BenchmarkSpec | None = None,
) -> Decimal:
    """Return the g-spread in basis points against a curve benchmark."""
    if benchmark is None:
        benchmark = BenchmarkSpec.interpolated()
    if benchmark.kind is BenchmarkKind.EXPLICIT and benchmark.explicit_yield is not None:
        bench_yield = benchmark.explicit_yield
    else:
        if isinstance(maturity, Tenor):
            bench_yield = curve.yield_for_tenor(maturity, spec=benchmark)
        else:
            bench_yield = curve.yield_for_date(maturity, spec=benchmark)
    return g_spread(bond_yield, bench_yield)


@dataclass(frozen=True, slots=True)
class GSpreadCalculator:
    """Curve-backed g-spread calculator returning basis-point outputs."""

    curve: GovernmentCurve

    def spread_bps(
        self,
        bond: Bond,
        bond_yield: object,
        *,
        benchmark: BenchmarkSpec | None = None,
    ) -> Decimal:
        """Return the g-spread in basis points for `bond`."""
        maturity = bond.maturity_date()
        return g_spread_with_benchmark(bond_yield, self.curve, maturity, benchmark=benchmark)


__all__ = ["GSpreadCalculator", "g_spread", "g_spread_with_benchmark"]
