"""Pure helpers for the promotion correlation backstop (B1): build the equal-weight deploy-book daily
return series and correlate a promotion candidate against it. A candidate promotes only if its daily-return
correlation to the current deploy book is below the policy threshold (or the book is empty — the first edge
trivially diversifies). An indeterminate correlation (too little overlap) withholds promotion — the safe,
capital-adjacent error."""
from __future__ import annotations

import math


def deploy_book_returns(returns_by_sid: dict[str, dict[str, float]]) -> dict[str, float]:
    per_date: dict[str, list[float]] = {}
    for series in returns_by_sid.values():
        for d, r in series.items():
            per_date.setdefault(d, []).append(r)
    return {d: sum(v) / len(v) for d, v in per_date.items()}


def corr_to_book(candidate: dict[str, float], book: dict[str, float], min_overlap: int) -> float | None:
    dates = sorted(set(candidate) & set(book))
    if len(dates) < min_overlap:
        return None
    a = [candidate[d] for d in dates]
    b = [book[d] for d in dates]
    n = len(dates)
    ma, mb = sum(a) / n, sum(b) / n
    cov = sum((x - ma) * (y - mb) for x, y in zip(a, b, strict=True))
    va = sum((x - ma) ** 2 for x in a)
    vb = sum((y - mb) ** 2 for y in b)
    if va <= 0.0 or vb <= 0.0:
        return None
    return cov / math.sqrt(va * vb)


def passes_backstop(corr: float | None, *, book_empty: bool, max_corr: float) -> bool:
    if book_empty:
        return True
    return corr is not None and corr < max_corr
