"""PURE intraday `worst_basis` computation — the delta-neutral carry's deepest INTRADAY mark-to-market,
the tail the daily-close basis accounting is blind to.

A cash-and-carry carry position is LONG spot + SHORT perp; its price P&L over a minute is
`spot_1m_ret − perp_1m_ret`. Within a day the position's running mark = the CUMULATIVE sum of those
per-minute basis steps from the day's first aligned minute. `worst_basis(day)` = the MINIMUM of that
running cumulative basis over the day — the worst the delta-neutral leg ever marked intraday (where a
LUNA-class mid-day liquidation lives), even when the position recovers to a benign daily-CLOSE basis.

Probed against LUNAUSDT 1m: 2022-05-12 worst_basis ≈ −163% while the daily-close basis was only −0.7%.

Pure; no I/O. Inputs are aligned-on-common-minute perp+spot 1m closes ({epoch_ms: close}); the caller
(the Bybit klines adapter) supplies them. Negative cumulative = the carry losing; worst_basis ≤ 0 by
construction (the running sum starts at 0 at the first aligned minute).
"""
from __future__ import annotations

_DAY_MS = 86_400_000


def worst_basis_by_day(*, perp_close: dict[int, float],
                       spot_close: dict[int, float]) -> dict[int, float]:
    """`{epoch_day: worst_basis}` over the perp+spot 1m closes ALIGNED on their common minute timestamps.

    For each day (epoch_day = epoch_ms // 86_400_000): walk the day's aligned minutes in ascending time;
    maintain `cum` = running Σ(spot_1m_ret − perp_1m_ret) seeded at 0 at the day's first aligned minute;
    each subsequent aligned minute adds `(spot_t/spot_{t-1} − 1) − (perp_t/perp_{t-1} − 1)` where t-1 is
    the PRIOR aligned minute (a step whose prior or current close is ≤ 0 is skipped — bad/zero bar). The
    day's `worst_basis` = min(cum) over the day (= 0 when the basis only ever rises). A day with fewer than
    2 aligned minutes (no return step) gets NO entry. Pure; no I/O."""
    common = sorted(set(perp_close) & set(spot_close))
    if len(common) < 2:
        return {}

    # Bucket aligned minutes by epoch_day, preserving ascending time order.
    by_day: dict[int, list[int]] = {}
    for ms in common:
        by_day.setdefault(ms // _DAY_MS, []).append(ms)

    out: dict[int, float] = {}
    for day, minutes in by_day.items():
        if len(minutes) < 2:
            continue                      # single aligned bar in the day -> no return step -> no entry
        cum = 0.0
        worst = 0.0                       # the running sum starts at 0 at the first aligned minute
        prev_ms = minutes[0]
        for ms in minutes[1:]:
            sp_prev, sp_cur = spot_close[prev_ms], spot_close[ms]
            pp_prev, pp_cur = perp_close[prev_ms], perp_close[ms]
            prev_ms = ms
            if sp_prev <= 0.0 or pp_prev <= 0.0 or sp_cur <= 0.0 or pp_cur <= 0.0:
                continue                  # bad/zero bar -> can't form a clean return; skip the step
            step = (sp_cur / sp_prev - 1.0) - (pp_cur / pp_prev - 1.0)
            cum += step
            if cum < worst:
                worst = cum
        out[day] = worst
    return out
