"""Live-booking token-unlock dilution-short paper track (ForwardStrategy contract).
Books the REAL market-neutral return (short the in-window cliff names + long BTC, squeeze-stopped) forward
each day. Mirrors XsFundingForward: advance(last_date, extra) -> (rows, extra). The unlevered, gross-1
market-neutral edge return is booked; deployment leverage/vol-target is a sizing decision applied later."""
from __future__ import annotations

import datetime as dt
from typing import Any, Callable

from fxhnt.domain.unlock_shorts import short_leg_pnl, supply_shock


def _today() -> str:
    return dt.date.today().isoformat()


def _epoch_day(iso: str) -> int:
    return (dt.date.fromisoformat(iso) - dt.date(1970, 1, 1)).days


class UnlockShortForward:
    def __init__(self, live: Any, *, min_shock: float = 0.1, min_qvol: float = 5e6,
                 daily_stop: float = 0.15, max_name_weight: float = 0.25, cost_bps: float = 10.0,
                 clock: Callable[[], str] = _today) -> None:
        self._live = live
        self._min_shock = min_shock
        self._min_qvol = min_qvol
        self._stop = daily_stop
        self._maxw = max_name_weight
        self._cost = cost_bps / 1e4
        self._clock = clock

    def advance(self, last_date: str | None, extra: dict[str, Any]) -> tuple[list[tuple[str, float]], dict[str, Any]]:
        today = self._clock()
        prev_pos: dict[str, float] = extra.get("positions", {})
        prev_perp: dict[str, float] = extra.get("perp", {})
        prev_btc: float = extra.get("btc", 0.0)
        snap = self._live.snapshot(set(prev_pos), _epoch_day(today))
        prices: dict[str, tuple[float, float]] = snap["prices"]
        btc: float = snap["btc"]
        window: dict[str, dict[str, Any]] = snap["window"]

        # 1) new market-neutral book: in-window names that clear liquidity + supply-shock, equal-weight capped
        elig = {}
        for s, d in window.items():
            sh = supply_shock(d["n"], d["perp"], d["qvol"])
            if d["qvol"] >= self._min_qvol and sh is not None and sh > self._min_shock:
                elig[s] = d
        new_w: dict[str, float] = {}
        if elig:
            w0 = min(1.0 / len(elig), self._maxw)
            raw = {s: w0 for s in elig}
            g = sum(raw.values())
            new_w = {s: v / g for s, v in raw.items()}      # gross 1

        # 2) book the PRIOR book's realized 1-day market-neutral return (short name + long BTC, stopped)
        rows: list[tuple[str, float]] = []
        if prev_pos and prev_btc > 0 and btc > 0:
            btc_ret = btc / prev_btc - 1.0
            realized = 0.0
            for s, w in prev_pos.items():
                if s in prices and prev_perp.get(s, 0.0) > 0:
                    cur, fund = prices[s]
                    name_ret = cur / prev_perp[s] - 1.0
                    realized += w * short_leg_pnl(name_ret, btc_ret, fund, daily_stop=self._stop)
            turnover = sum(abs(new_w.get(s, 0.0) - prev_pos.get(s, 0.0)) for s in set(new_w) | set(prev_pos))
            rows.append((today, realized - turnover * self._cost / 2.0))

        # 3) carry the new book forward
        extra = {"positions": new_w, "perp": {s: window[s]["perp"] for s in new_w}, "btc": btc}
        return rows, extra
