# ---
# jupyter:
#   jupytext:
#     formats: ipynb,py:percent
#     text_representation:
#       extension: .py
#       format_name: percent
#       format_version: '1.3'
#       jupytext_version: 1.19.1
#   kernelspec:
#     display_name: Python 3
#     language: python
#     name: python3
# ---

# %% [markdown]
# # Engine curve-builder examples
#
# This notebook shows:
#
# - named discount, government, and benchmark curve construction
# - curve retrieval and interpolation
# - downstream use in bond analytics

# %%
from __future__ import annotations

import sys
from decimal import Decimal
from pathlib import Path

root = Path.cwd()
if (root / "src").exists():
    sys.path.insert(0, str(root / "src"))
elif (root.parent / "src").exists():
    sys.path.insert(0, str(root.parent / "src"))

# %% [markdown]
# ## Imports

# %%
from dataclasses import replace  # noqa: E402

from fuggers_py.bonds.instruments import FixedBond  # noqa: E402
from fuggers_py.bonds.types import YieldCalculationRules  # noqa: E402
from fuggers_py.core import Currency, Date, Frequency  # noqa: E402
from fuggers_py.engine import CurveBuilder, PricingRouter  # noqa: E402
from fuggers_py.data import (
    AnalyticsCurves,
    CurveId,
    CurvePoint,
    InstrumentId,
    PricingSpec,
)

# %% [markdown]
# ## Define the curve pillars

# %%
settlement = Date.from_ymd(2026, 1, 15)
discount_points = [
    CurvePoint(Decimal("0.25"), Decimal("0.0450")),
    CurvePoint(Decimal("0.50"), Decimal("0.0445")),
    CurvePoint(Decimal("1.00"), Decimal("0.0435")),
    CurvePoint(Decimal("2.00"), Decimal("0.0415")),
    CurvePoint(Decimal("5.00"), Decimal("0.0395")),
    CurvePoint(Decimal("10.00"), Decimal("0.0400")),
]
government_points = [
    CurvePoint(Decimal("0.25"), Decimal("0.0420")),
    CurvePoint(Decimal("0.50"), Decimal("0.0410")),
    CurvePoint(Decimal("1.00"), Decimal("0.0400")),
    CurvePoint(Decimal("2.00"), Decimal("0.0385")),
    CurvePoint(Decimal("5.00"), Decimal("0.0370")),
    CurvePoint(Decimal("10.00"), Decimal("0.0380")),
]
benchmark_points = [
    CurvePoint(Decimal("0.25"), Decimal("0.0435")),
    CurvePoint(Decimal("0.50"), Decimal("0.0428")),
    CurvePoint(Decimal("1.00"), Decimal("0.0418")),
    CurvePoint(Decimal("2.00"), Decimal("0.0402")),
    CurvePoint(Decimal("5.00"), Decimal("0.0388")),
    CurvePoint(Decimal("10.00"), Decimal("0.0392")),
]

# %% [markdown]
# ## Build named curves

# %%
builder = CurveBuilder()
discount_curve = builder.add_zero_curve(CurveId("usd.discount"), discount_points, settlement)
government_curve = builder.add_zero_curve(CurveId("usd.government"), government_points, settlement)
benchmark_curve = builder.add_zero_curve(CurveId("usd.benchmark"), benchmark_points, settlement)

discount_curve, government_curve, benchmark_curve

# %% [markdown]
# ## Retrieve a curve and interpolate an interior tenor

# %%
retrieved_curve = builder.get("usd.discount")
interior_zero_rate = retrieved_curve.zero_rate_at_tenor(3.0)
five_year_discount_factor = retrieved_curve.discount_factor(settlement.add_years(5))

print("3Y zero rate:", interior_zero_rate)
print("5Y discount factor:", five_year_discount_factor)

# %% [markdown]
# ## Use the builder output in downstream analytics

# %%
rules = replace(YieldCalculationRules.us_corporate(), frequency=Frequency.SEMI_ANNUAL)
bond = FixedBond.new(
    issue_date=Date.from_ymd(2024, 1, 15),
    maturity_date=Date.from_ymd(2031, 1, 15),
    coupon_rate=Decimal("0.0450"),
    frequency=Frequency.SEMI_ANNUAL,
    currency=Currency.USD,
    notional=Decimal("100"),
    rules=rules,
)

router = PricingRouter()
curves = AnalyticsCurves(
    discount_curve=discount_curve,
    government_curve=government_curve,
    benchmark_curve=benchmark_curve,
)
result = router.price(
    bond,
    settlement,
    instrument_id=InstrumentId("SCENARIO-A-FIXED"),
    market_price=Decimal("101.25"),
    pricing_spec=PricingSpec(compute_spreads=True, compute_key_rates=True, include_asset_swap=True),
    curves=curves,
)

print("Clean price:", result.clean_price)
print("Yield to maturity:", result.yield_to_maturity)
print("Z-spread:", result.z_spread)
print("Key-rate tenors:", sorted(result.key_rate_durations))
