"""C2: no `*_nav` asset may raise on a data-provider/pre-tracker failure — a broken track degrades to a
stale (unchanged) row so the Dagster step always succeeds and the downstream `cockpit_forward` gate is never
skipped. These tests pin the two known offenders: multistrat_nav's pre-tracker Yahoo snapshot loop, and
`_run_paper_tracker`'s isolation of the databento provider error base."""
from __future__ import annotations


def test_multistrat_nav_survives_yahoo_snapshot_failure(tmp_path, monkeypatch):
    """multistrat_nav's `snapshot_yahoo_closes` loop runs OUTSIDE `_run_paper_tracker`. A Yahoo fetch failure
    there must DEGRADE to a no-op return (record unchanged), not raise out of the asset and skip the gate."""
    from dagster import build_op_context

    import fxhnt.adapters.orchestration.assets as assets
    from fxhnt.config import Settings

    monkeypatch.setattr("fxhnt.config.get_settings",
                        lambda: Settings(operational_dsn=f"sqlite:///{tmp_path / 'op.db'}"))

    class _BoomYahoo:
        def adj_closes(self, sym):   # noqa: ANN001, ANN202
            raise ConnectionError("yahoo unreachable")
    monkeypatch.setattr("fxhnt.adapters.data.yahoo_daily.YahooDailyClient", _BoomYahoo)

    ran = {"tracker": False}

    def _fake_tracker(*a, **k):
        ran["tracker"] = True
        return {"forward_days": 5, "last_date": "2026-07-13", "reinception": False}
    monkeypatch.setattr(assets, "_run_paper_tracker", _fake_tracker)

    out = assets.multistrat_nav(build_op_context())
    assert out == {"forward_days": 0, "last_date": None, "reinception": False}   # degraded, record unchanged
    assert not ran["tracker"]        # pre-tracker snapshot failed → do not recompute; leave the record as-is


def test_run_paper_tracker_isolates_databento_provider_error(tmp_path, monkeypatch):
    """A databento provider error (BentoError/BentoClientError) raised while building/recomputing a track must
    be isolated (warn + no-op dict), not propagate and skip the gate — the same way transient net errors are."""
    from dagster import build_op_context
    from databento.common.error import BentoClientError

    import fxhnt.adapters.orchestration.assets as assets
    from fxhnt.config import Settings

    monkeypatch.setattr("fxhnt.config.get_settings",
                        lambda: Settings(operational_dsn=f"sqlite:///{tmp_path / 'op.db'}"))

    def _boom():
        raise BentoClientError(http_status=422, message="data_end_after_available_end")

    out = assets._run_paper_tracker(build_op_context(), "vrp_nav", _boom)
    assert out == {"forward_days": 0, "last_date": None, "reinception": False}


def test_run_paper_tracker_lets_real_logic_bugs_stay_loud(tmp_path, monkeypatch):
    """The isolation is for data-provider/network errors ONLY — a genuine strategy-math bug (KeyError/
    ValueError) must still propagate loudly, never be swallowed by a bare `except Exception`."""
    from dagster import build_op_context

    import fxhnt.adapters.orchestration.assets as assets
    from fxhnt.config import Settings

    monkeypatch.setattr("fxhnt.config.get_settings",
                        lambda: Settings(operational_dsn=f"sqlite:///{tmp_path / 'op.db'}"))

    def _bug():
        raise ValueError("genuine strategy math bug")

    try:
        assets._run_paper_tracker(build_op_context(), "vrp_nav", _bug)
        raise AssertionError("expected the ValueError to propagate loudly")
    except ValueError:
        pass
