# ---
# 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]
# # Extension layer examples
#
# This notebook shows:
#
# - file-backed market and reference data adapters
# - explicit empty reference-data sources
# - SQLite-backed trait storage
# - deterministic in-memory portfolio snapshots
# - JSON codec round-trips for representative payloads

# %%
from __future__ import annotations

import sys
from decimal import Decimal
from pathlib import Path
from tempfile import TemporaryDirectory

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"))
    root = root.parent

fixtures = root / "tests" / "data"

# %% [markdown]
# ## Imports

# %%
from fuggers_py.core import Date  # noqa: E402
from fuggers_py.io import (  # noqa: E402
    EmptyBondReferenceSource,
    EmptyEtfHoldingsSource,
    EmptyIssuerReferenceSource,
    EmptyRatingSource,
    InMemoryPortfolioStore,
    JsonCodec,
    PortfolioFilter,
    SQLiteStorageAdapter,
    StoredPortfolio,
    StoredPosition,
    create_file_market_data,
    create_file_reference_data,
)
from fuggers_py.data import (
    CurveId,
    CurvePoint,
    InstrumentId,
    PortfolioId,
    PricingSpec,
    QuoteSide,
    ReferenceDataProvider,
)
from fuggers_py.io import (
    CurveConfig,
    CurveSnapshot,
    OverrideRecord,
    Pagination,
    PricingConfig,
)

# %% [markdown]
# ## Load market data from files

# %%
market_data = create_file_market_data(
    quotes_csv=fixtures / "quotes.csv",
    curve_inputs_json=fixtures / "curve_inputs.json",
    fixings_csv=fixtures / "fixings.csv",
)

# %%
quote = market_data.get_quote("US1234567890", QuoteSide.ASK)
curve_inputs = market_data.get_curve_inputs("usd.discount")
fixing = market_data.get_fixing("SOFR", Date.from_ymd(2026, 3, 13))

quote, curve_inputs, fixing

# %% [markdown]
# ## Load bond reference data from files

# %%
reference_data = create_file_reference_data(bonds_csv=fixtures / "bonds.csv")

# %%
bond_reference = reference_data.get_bond_reference(InstrumentId("US1234567890"))
callable_reference = reference_data.get_bond_reference("US0987654321")

bond_reference, callable_reference

# %% [markdown]
# ## Use explicit empty reference-data sources

# %%
empty_reference_data = ReferenceDataProvider(
    bond_source=EmptyBondReferenceSource(),
    issuer_source=EmptyIssuerReferenceSource(),
    rating_source=EmptyRatingSource(),
    etf_holdings_source=EmptyEtfHoldingsSource(),
)

# %%
empty_reference_data.get_bond_reference("US1234567890"), empty_reference_data.get_etf_holdings("fixture-etf")

# %% [markdown]
# ## Save and load through SQLite storage

# %%
with TemporaryDirectory() as tmp_dir:
    db_path = Path(tmp_dir) / "example.sqlite"
    storage = SQLiteStorageAdapter(db_path)

    storage.bond_store.upsert_bond_reference(bond_reference)
    storage.curve_store.upsert_curve_config(
        CurveConfig(curve_id=CurveId("usd.discount"), curve_kind="zero", interpolation="linear", source="example")
    )
    storage.curve_store.insert_curve_snapshot(
        CurveSnapshot(
            curve_id=CurveId("usd.discount"),
            reference_date=Date.from_ymd(2026, 3, 13),
            points=(
                CurvePoint(Decimal("1.0"), Decimal("0.0425")),
                CurvePoint(Decimal("5.0"), Decimal("0.0390")),
            ),
            source="example",
        )
    )
    storage.config_store.upsert_pricing_config(
        PricingConfig(config_id="base", pricing_spec=PricingSpec(quote_side=QuoteSide.MID), source="example")
    )
    storage.override_store.save_override(
        OverrideRecord(
            scope_id="US1234567890",
            field_name="spread",
            value="0.0010",
            numeric_value=Decimal("0.0010"),
            side=QuoteSide.MID,
            effective_date=Date.from_ymd(2026, 3, 13),
            source="manual",
        ),
        actor="example",
    )

    stored_bond = storage.get_bond_reference("US1234567890")
    stored_curve = storage.get_curve_snapshot("usd.discount")
    stored_config = storage.get_pricing_config("base")
    stored_overrides = storage.list_overrides("US1234567890", Pagination(limit=10))
    audit_entries = storage.list_audit_entries()
    storage.close()

stored_bond, stored_curve, stored_config, stored_overrides, audit_entries

# %% [markdown]
# ## Store lightweight portfolio snapshots in memory

# %%
portfolio_store = InMemoryPortfolioStore(
    [
        StoredPortfolio(
            portfolio_id=PortfolioId("example-portfolio"),
            positions=(
                StoredPosition(instrument_id=InstrumentId("US1234567890"), quantity=Decimal("100")),
                StoredPosition(instrument_id=InstrumentId("US0987654321"), weight=Decimal("0.35")),
            ),
            as_of=Date.from_ymd(2026, 3, 13),
            source="example",
            name="Example Core",
        ),
        StoredPortfolio(
            portfolio_id=PortfolioId("example-portfolio"),
            positions=(
                StoredPosition(instrument_id=InstrumentId("US1234567890"), quantity=Decimal("110")),
                StoredPosition(instrument_id=InstrumentId("US1111111111"), weight=Decimal("0.20")),
            ),
            as_of=Date.from_ymd(2026, 3, 14),
            source="example",
            name="Example Core",
        ),
    ]
)

# %%
latest_portfolio = portfolio_store.get_portfolio("example-portfolio")
filtered_portfolios = portfolio_store.list_portfolios(
    PortfolioFilter(source="example", instrument_id=InstrumentId("US1234567890"))
)

latest_portfolio, filtered_portfolios

# %% [markdown]
# ## JSON encode/decode a representative payload

# %%
codec = JsonCodec()
payload = {
    "bond_reference": bond_reference,
    "curve_id": CurveId("usd.discount"),
    "quote_side": QuoteSide.MID,
    "value": Decimal("101.25"),
}

# %%
encoded = codec.encode(payload)
decoded = codec.decode(encoded)

encoded.decode("utf-8"), decoded
