"""The declared, return-affecting definition of a forward track and its content hash.

A CHANGE to the hash means the strategy's return-generating definition changed → the forward engine
auto-re-inceptions (spec sub-project A §2/§3). The hash covers the declared params (instrument list,
cost bps, universe key, sleeve set, key constants) PLUS an explicit `version` int the dev bumps for
pure-code changes the params don't capture. It never covers comments/refactors, so it never spuriously
re-inceptions; erring toward extra re-inception (a changed strategy re-proving itself OOS) is the safe
direction for real money."""
from __future__ import annotations

import hashlib
import json

from fxhnt.registry import STRATEGY_REGISTRY


def definition_hash(params: dict, version: int) -> str:
    canonical = json.dumps(params, sort_keys=True, separators=(",", ":"))
    return hashlib.sha256(f"{canonical}|v{version}".encode()).hexdigest()


def track_definition(strategy_id: str) -> tuple[dict, int, str]:
    """Return (params, version, record_mode) for a track. Raises KeyError if the track has no `definition`
    (a plan/registry error — every tracked strategy must declare one)."""
    d = STRATEGY_REGISTRY[strategy_id]["definition"]
    return d["params"], int(d["version"]), d["record_mode"]


def inception_override(strategy_id: str) -> str | None:
    """The declared canonical inception date (OOS-clock start) for a track's CURRENT definition, or None to
    fall back to `today`. A FAITHFUL venue/cost re-home (same edge + PIT data, `record_mode: recompute`)
    changes the definition hash and would otherwise restart the OOS clock at today; declaring
    `"inception_t0": {"date": ..., "version": ...}` at the definition's top level pins the real pre-re-home
    start, so a fresh DB rebuild reproduces the recovered window from git (the SSOT) instead of a manual anchor
    backdate. It lives OUTSIDE `params` → NOT hashed → declaring/altering it never itself re-inceptions.
    VERSION-PINNED: honored ONLY when its `version` equals the definition's current `version`, so a genuine
    re-tune (which bumps `version`) auto-ignores a now-stale override and correctly gets a fresh today-clock."""
    d = STRATEGY_REGISTRY[strategy_id]["definition"]
    ov = d.get("inception_t0")
    if ov is None or int(ov["version"]) != int(d["version"]):
        return None
    return str(ov["date"])
