"""Per-track (state_file, build_strategy) map for the one-time forward migration (Task 8).

DRY against `assets.py`: each entry copies the EXACT `build_strategy` construction (same adapters, same
dependency wiring) and the exact `state_file` basename its `*_nav` asset uses, so `migrate_track`'s recompute
reconcile runs the strategy at the SAME basis the live forward track books. `combined` DOES need an entry
despite being `record_mode="recompute"`: production has a pre-branch `forward_summary["combined"]` row (the
old ingest wrote all tracks), so without a seeded anchor the first `forward_engine.run_track` sees
`active_anchor("combined") is None` but `has_forward_history("combined") is True` and the lost-anchor guard
raises. `migrate_track` will report `diverged` for it (the old ForwardTracker-level killswitch was dropped in
Task 8c, so the recompute no longer matches the accumulated JSON nav) — that is expected/benign; the anchor
still gets seeded from the JSON T0, and the engine then replaces the record on its next run.

NOTE (Phase 0b): `xsfunding` was `record_mode="observed"` (legacy-venue-scoped `XsFundingForward`) when this
module was written, so it mapped to a harmless `lambda: None` (an observed strategy is never recomputed by
`migrate_track`). It is now `record_mode="recompute"` (its own Bybit single-sleeve track, mirroring
`positioning` — see `build_bybit_sleeve_forward_nav`), so it gets a real builder below like every other
recompute track; a stale `lambda: None` would crash `recompute_series` (`None.advance`) if this one-time
migration is ever re-run against a leftover pre-migration `xsfunding_state.json`.

NOTE (Phase 0b, Task 2): `unlock` was ALREADY `record_mode="recompute"` (unlike xsfunding's pre-migration
"observed"), so its builder here was never a `lambda: None` stub — but it built the OLD standalone legacy-venue
`UnlockShortForward` construction. That construction is retired (its `unlock_nav`
asset now uses the SAME Bybit single-sleeve `BybitFourEdgeStrategy(sleeves=["unlock"], unlock_events=...)`
xsfunding/positioning use), so the builder below was updated to match — otherwise this one-time migration's
recompute reconcile would run a DIFFERENT strategy than the live track books, producing a false `diverged`
verdict (or worse, silently reconciling against the wrong basis)."""
from __future__ import annotations

from collections.abc import Callable
from typing import Any

from fxhnt.application.forward_tracker import ForwardStrategy
from fxhnt.config import Settings

TrackBuilders = dict[str, tuple[str, Callable[[], ForwardStrategy]]]


def track_builders(settings: Settings, data_dir: str) -> TrackBuilders:
    """strategy_id -> (state_file basename, build_strategy), one entry per `STRATEGY_REGISTRY` id."""
    builders: TrackBuilders = {}

    # (the "combined" crypto-momentum book was RETIRED 2026-07-11 — removed from the registry, so
    # migrate_forward_anchors no longer iterates to it; its builder is gone.)

    # ---- sixtyforty_nav: 60/40 baseline (Tiingo native total-return adjClose) -------------------------
    def _build_sixtyforty() -> Any:
        from fxhnt.adapters.data.tiingo_daily import TiingoDailyClient
        from fxhnt.application.paper_strategies import SixtyFortyStrategy

        return SixtyFortyStrategy(TiingoDailyClient())

    builders["sixtyforty"] = ("sixtyforty_state", _build_sixtyforty)

    # ---- multistrat_nav: adaptive multi-strat book (5 ETFs) on the frozen Yahoo PIT series --------------
    def _build_multistrat() -> Any:
        from fxhnt.adapters.data.yahoo_pit import YahooPitClient
        from fxhnt.adapters.persistence.forward_nav import ForwardNavRepo
        from fxhnt.application.paper_strategies import MultiStratStrategy
        from fxhnt.domain.strategies.multistrat import FUND_INSTRUMENTS

        repo = ForwardNavRepo(settings.operational_dsn)
        return MultiStratStrategy(YahooPitClient(repo), instruments=FUND_INSTRUMENTS)

    builders["multistrat"] = ("multistrat_state", _build_multistrat)

    # (crypto_tstrend / stablecoin_rotation builders RETIRED 2026-07-13, Phase 0b Task 4 — both standalone
    # legacy-venue registry entries are gone, so `migrate_forward_anchors` no longer iterates to either sid; the
    # builders here are gone with them. crypto_tstrend the BYBIT BOOK SLEEVE is unaffected — that lives
    # under `bybit_4edge`'s own builder below, not here.)

    # ---- unlock_nav: single-sleeve unlock edge on the liquid universe (Phase 0b Task 2: own Bybit track, ----
    # ---- the SAME single-sleeve construction as xsfunding/positioning, mirrored here; carries the unlock ----
    # ---- calendar the sleeve needs, unlike xsfunding/positioning) --------------------------------------------
    def _build_unlock() -> Any:
        from fxhnt.adapters.warehouse.timescale_feature_store import TimescaleFeatureStore
        from fxhnt.application.bybit_forward_track import BybitFourEdgeStrategy
        from fxhnt.application.bybit_liquidity import liquid_universe
        from fxhnt.application.unlock_calendar_loader import load_unlock_events, operational_unlock_repo

        store = TimescaleFeatureStore(settings.operational_dsn, table="bybit_features")
        universe = liquid_universe(store) or None
        unlock_events = load_unlock_events(operational_unlock_repo(settings),
                                           f"{data_dir}/unlock_calendar.json")
        return BybitFourEdgeStrategy(
            store, universe=universe, cost_bps=settings.bybit_cost_bps, sleeves=["unlock"],
            unlock_events=unlock_events)

    builders["unlock"] = ("unlock_state", _build_unlock)

    # ---- bybit_4edge_nav: naive eq-wt 4-sleeve Bybit book on the liquid universe -------------------------
    # NOTE: unlike assets.py (which closes the store in a `finally` AFTER the full ForwardTracker.step()
    # completes), the store here must stay OPEN past this function's return — the caller invokes
    # `strategy.advance()` later (inside `recompute_series`), which reads from `store`. It is intentionally
    # left open for the process lifetime of this one-time migration CLI.
    def _build_bybit_4edge() -> Any:
        from fxhnt.adapters.warehouse.timescale_feature_store import TimescaleFeatureStore
        from fxhnt.application.bybit_forward_track import (
            POSITIONING_COIN_GROSS_CAP,
            POSITIONING_TAIL_CAP_K,
            BybitFourEdgeStrategy,
        )
        from fxhnt.application.bybit_liquidity import liquid_universe
        from fxhnt.application.unlock_calendar_loader import load_unlock_events, operational_unlock_repo

        store = TimescaleFeatureStore(settings.operational_dsn, table="bybit_features")
        universe = liquid_universe(store) or None
        unlock_events = load_unlock_events(operational_unlock_repo(settings),
                                           f"{data_dir}/unlock_calendar.json")
        return BybitFourEdgeStrategy(
            store, universe=universe, cost_bps=settings.bybit_cost_bps,
            unlock_events=unlock_events, positioning_capacity_capital=settings.paper_capital,
            positioning_tail_cap_k=POSITIONING_TAIL_CAP_K,
            positioning_coin_gross_cap=POSITIONING_COIN_GROSS_CAP)

    builders["bybit_4edge"] = ("bybit_4edge_state", _build_bybit_4edge)

    # ---- bybit_4edge_levered_nav: observe-only levered shadow (static leverage, book-gross <= 1.5x) -------
    def _build_bybit_4edge_levered() -> Any:
        from fxhnt.adapters.warehouse.timescale_feature_store import TimescaleFeatureStore
        from fxhnt.application.bybit_forward_track import (
            _LEVERED_SLEEVE_SHAPE,
            MAX_BOOK_GROSS,
            POSITIONING_COIN_GROSS_CAP,
            POSITIONING_TAIL_CAP_K,
            BybitFourEdgeStrategy,
        )
        from fxhnt.application.bybit_liquidity import liquid_universe
        from fxhnt.application.unlock_calendar_loader import load_unlock_events, operational_unlock_repo

        store = TimescaleFeatureStore(settings.operational_dsn, table="bybit_features")
        universe = liquid_universe(store) or None
        unlock_events = load_unlock_events(operational_unlock_repo(settings),
                                           f"{data_dir}/unlock_calendar.json")
        return BybitFourEdgeStrategy(
            store, universe=universe, cost_bps=settings.bybit_cost_bps,
            unlock_events=unlock_events, leverage_shape=_LEVERED_SLEEVE_SHAPE, max_gross=MAX_BOOK_GROSS,
            positioning_capacity_capital=settings.paper_capital,
            positioning_tail_cap_k=POSITIONING_TAIL_CAP_K,
            positioning_coin_gross_cap=POSITIONING_COIN_GROSS_CAP)

    builders["bybit_4edge_levered"] = ("bybit_4edge_levered_state", _build_bybit_4edge_levered)

    # ---- positioning_nav: single-sleeve positioning edge on the liquid universe --------------------------
    def _build_positioning() -> Any:
        from fxhnt.adapters.warehouse.timescale_feature_store import TimescaleFeatureStore
        from fxhnt.application.bybit_forward_track import (
            POSITIONING_COIN_GROSS_CAP,
            POSITIONING_TAIL_CAP_K,
            BybitFourEdgeStrategy,
        )
        from fxhnt.application.bybit_liquidity import liquid_universe

        store = TimescaleFeatureStore(settings.operational_dsn, table="bybit_features")
        universe = liquid_universe(store) or None
        return BybitFourEdgeStrategy(
            store, universe=universe, cost_bps=settings.bybit_cost_bps, sleeves=["positioning"],
            positioning_capacity_capital=settings.paper_capital,
            positioning_tail_cap_k=POSITIONING_TAIL_CAP_K,
            positioning_coin_gross_cap=POSITIONING_COIN_GROSS_CAP)

    builders["positioning"] = ("positioning_state", _build_positioning)

    # ---- xsfunding_nav: single-sleeve xsfunding edge on the liquid universe (Phase 0b: own Bybit track, -----
    # ---- the SAME single-sleeve construction as positioning, mirrored here) --------------------------------
    def _build_xsfunding() -> Any:
        from fxhnt.adapters.warehouse.timescale_feature_store import TimescaleFeatureStore
        from fxhnt.application.bybit_forward_track import BybitFourEdgeStrategy
        from fxhnt.application.bybit_liquidity import liquid_universe

        store = TimescaleFeatureStore(settings.operational_dsn, table="bybit_features")
        universe = liquid_universe(store) or None
        return BybitFourEdgeStrategy(
            store, universe=universe, cost_bps=settings.bybit_cost_bps, sleeves=["xsfunding"])

    builders["xsfunding"] = ("xsfunding_state", _build_xsfunding)

    return builders
