"""Deposit-flight playbook, step 9: quiet accounts score higher at the last re-score.

Four batch re-scores as of days 93, 100, 107 and 114 of the book, a week apart:
the leaving accounts have gone quiet and have not left yet, so they keep
their event histories and only the observation instant moves. With
observation time on, each re-score records `as_of` and the quiet state, and
the quiet accounts' median risk is higher at the last re-score than at the
first: the silence alone moved it. With it off, every
quiet account scores the same at every re-score, and this step fails: the
playbook proves the capability, not the prose.
"""

import sys
from datetime import datetime, timedelta
from itertools import pairwise
from pathlib import Path
from statistics import median

sys.path.insert(0, str(Path(__file__).resolve().parents[1]))  # playbooks/playbook_api.py
from playbook_api import Api, State

api, state = Api(), State("deposit-flight")

first = datetime.fromisoformat(state["rescore_from"].replace("Z", "+00:00"))
count = int(state["rescores"])
cutoffs = [first + timedelta(days=7 * index) for index in range(count)]
label = "deposit_flight_45d"
for index, cutoff in enumerate(cutoffs):
    refresh = api.post(
        "/slots/deposits/refreshes",
        {"cutoff": cutoff.strftime("%Y-%m-%dT%H:%M:%SZ")},
        key=f"deposit-flight-refresh-{index}",
    )
    refresh = api.wait(
        f"/slots/deposits/refreshes/{refresh['refresh_id']}",
        lambda item: item.get("status") in ("succeeded", "failed"),
        what=f"re-score {index + 1}",
    )
    print(f"re-score {index + 1}: {refresh['status']}")
    leavers = state["leavers"]
    scores, silences, observed = [], [], 0
    for account in leavers:
        served = api.get(f"/slots/deposits/entities/account/{account}/state")
        value = (served.get("scores") or {}).get(label)
        if isinstance(value, dict):
            value = value.get("p", value.get("score"))
        if isinstance(value, int | float):
            scores.append(float(value))
        observation = api.get(f"/slots/deposits/entities/account/{account}/observation")
        if observation.get("as_of") and observation.get("quiet_state"):
            observed += 1
            silences.append(int(observation["quiet_state"]["silence_seconds"]))
    state.update(
        **{
            f"quiet_{index}": {
                "median_score": median(scores) if scores else None,
                "median_silence": median(silences) if silences else None,
                "observed": observed,
            }
        }
    )

curve = [state[f"quiet_{index}"] for index in range(count)]
print("quiet accounts observed at their as-of: " + str(all(c["observed"] > 0 for c in curve)))
if not all(c["observed"] > 0 for c in curve):
    sys.exit("no quiet account carries as_of and a quiet state: observation time is off")
silence = [c["median_silence"] for c in curve]
risk = [c["median_score"] for c in curve]
grows = all(earlier < later for earlier, later in pairwise(silence))
print(f"silence grows between re-scores: {grows}")
print(f"quiet-account median risk higher at the last re-score than the first: {risk[0] < risk[-1]}")
print("risk curve: " + ", ".join(f"{value:.4f}" for value in risk))
if not (grows and risk[0] < risk[-1]):
    sys.exit(f"the quiet accounts' median risk was not higher at the last re-score: {risk}")
