"""One-time migration from the mutable *_state.json trackers to the DB anchor model (spec §6).

Preserve-T0-and-reconcile: seed the anchor from the JSON inception; for recompute tracks compare the
recompute over [T0, today] against the accumulated nav (a divergence is evidence the old record drifted —
flag it, do not silently overwrite); for observed tracks import the accumulated booked series verbatim
(it is the only record of those observations) and carry the book-state."""
from __future__ import annotations

import datetime as dt
from typing import Any

from fxhnt.adapters.persistence.forward_nav import ForwardNavRepo
from fxhnt.application.forward_definition import definition_hash, track_definition
from fxhnt.application.forward_recompute import derive_nav, recompute_series


def migrate_track(repo: ForwardNavRepo, strategy_id: str, state: dict[str, Any], strategy: Any,
                  today: str, at: dt.datetime, *, tol_frac: float = 0.02) -> dict[str, Any]:
    params, version, record_mode = track_definition(strategy_id)
    t0 = state["inception"]
    repo.set_anchor(strategy_id, t0=t0, definition_hash=definition_hash(params, version),
                    definition_version=version, params_json=params, record_mode=record_mode, at=at)

    if record_mode == "recompute":
        rows = [(d, r) for d, r in recompute_series(strategy, t0) if d <= today]
        recomputed_nav, _ = derive_nav(rows)
        recomputed = {d: n for d, n in recomputed_nav}
        missing = [day["date"] for day in state.get("days", []) if day["date"] not in recomputed]
        max_abs = 0.0
        for day in state.get("days", []):
            got = recomputed.get(day["date"])
            if got is not None:
                max_abs = max(max_abs, abs(got - day["nav"]) / max(abs(day["nav"]), 1e-9))
        status = "diverged" if (missing or max_abs > tol_frac) else "match"
        return {"mode": record_mode, "t0": t0, "status": status,
                "max_abs_nav_diff": max_abs, "missing_dates": len(missing)}

    # observed: import the accumulated booked returns verbatim + carry the book-state
    days = state.get("days", [])
    for day in days:
        if day["date"] >= t0:
            repo.append_record(strategy_id, day["date"], float(day["ret"]), at=at)
    extra = dict(state.get("extra", {}))
    if extra:
        repo.set_book_state(strategy_id, extra, at=at)
    return {"mode": record_mode, "t0": t0, "status": "imported", "n": len(days)}
