"""Deposit-flight playbook, step 8: serve with observation time on.

The bundle enables observation time (the registry re-checks the pinned
evidence), a batch slot serves it, and the slot records `as_of` and the
quiet state on every write, with 7- and 14-day silence thresholds.

The bundle readiness read (a dry run of the bundle request) names exactly
what needs an acknowledgement now: the failing advisory gates and the bundle
findings, each finding with the fingerprint of its facts. The step acknowledges
exactly that, under the operator's consent, and stops if anything needed was
not consented to. Without the readiness read, the bundle refusal lists the same.
"""

import json
import os
import sys
from pathlib import Path

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")

# The M16 switch this playbook proves: "on" (the default) builds, trains and
# serves with observation time; "off" runs the same chain without it, and the
# quiet-book step then fails, because nothing rises under silence.
FLAG_ON = os.environ.get("TESSERA_PLAYBOOK_OBSERVATION_TIME", "on") != "off"

model_id = state["models"]["on" if FLAG_ON else "off"]
body: dict = {"observation_time": {"enabled": True}} if FLAG_ON else {}
bundles = f"/models/{model_id}/bundles"


def needed() -> tuple[list[str], list[dict[str, str]], dict | None]:
    """Exactly the gates and findings a bundle request needs acknowledged now
    (and the bundle, when the fallback request needed nothing and created it).

    The readiness read (a dry run of the bundle request) names them; on a
    deployment without it, the bundle refusal lists the same facts. Either way
    nothing is assumed: a fixed list would be refused when a finding is absent.
    """
    status, readiness = api.attempt(
        "GET",
        f"/models/{model_id}/bundle-readiness",
        params={"observation_time": "true" if FLAG_ON else "false"},
    )
    if status == 200:
        if readiness.get("verdict") == "blocked":
            sys.exit(f"the bundle request is refused: {json.dumps(readiness)[:3000]}")
        return (
            list(readiness.get("acknowledge_gates") or []),
            [
                {"finding": entry["finding"], "fingerprint": entry["fingerprint"]}
                for entry in readiness.get("acknowledge_findings") or []
            ],
            None,
        )
    if status != 404:
        sys.exit(f"GET bundle-readiness: HTTP {status}: {json.dumps(readiness)[:3000]}")
    status, answer = api.attempt("POST", bundles, body, key="deposit-flight-bundle-review")
    if status < 400:
        return [], [], answer
    details = (answer.get("error") or {}).get("details") or []
    if not any(detail.get("reason") == "acknowledgement_required" for detail in details):
        sys.exit(f"POST {bundles}: HTTP {status}: {json.dumps(answer)[:3000]}")
    return (
        [
            detail["gate"]
            for detail in details
            if detail.get("type") == "promotion_gate" and detail.get("severity") == "advisory"
        ],
        [
            {"finding": detail["finding"], "fingerprint": detail["fingerprint"]}
            for detail in details
            if detail.get("type") == "bundle_finding"
        ],
        None,
    )


gates, findings, created = needed()
# Explicit consent only: the operator names the advisory gates and the bundle
# findings they accept, and the reason. What is needed must all be consented
# to; then exactly that is acknowledged, whether or not G1 happened to fail.
gate_consent = json.loads(os.environ.get("TESSERA_QUICKSTART_ACKNOWLEDGEMENT") or "{}")
finding_consent = json.loads(os.environ.get("TESSERA_PLAYBOOK_FINDINGS_ACKNOWLEDGEMENT") or "{}")
unconsented = [gate for gate in gates if gate not in gate_consent.get("gates", [])] + [
    entry["finding"]
    for entry in findings
    if entry["finding"] not in finding_consent.get("findings", [])
]
if unconsented:
    sys.exit(f"needs an acknowledgement the operator did not give: {', '.join(unconsented)}")
if gates:
    body["acknowledge_gates"] = {"gates": gates, "reason": gate_consent["reason"]}
if findings:
    body["acknowledge_findings"] = {"findings": findings, "reason": finding_consent["reason"]}
bundle = created if created is not None else api.post(bundles, body, key="deposit-flight-bundle")
slot = api.post(
    "/slots",
    {
        "environment": "test",
        "name": "deposits",
        "entity_type": "account",
        "mode": "live",
        "scoring": "batch_only",
    },
    key="deposit-flight-slot",
)
activated = api.post(f"/slots/{slot['slot_id']}:activate", {"bundle_id": bundle["bundle_id"]})
print(f"slot deposits active: {activated['active_bundle_id'] == bundle['bundle_id']}")
if FLAG_ON:
    config = api.put(
        "/slots/deposits/observation-time",
        {"enabled": True, "silence_thresholds": ["7d", "14d"], "maturation_lag": "0d"},
    )
    print(f"observation time on the slot: {config['enabled']}")
    if not config["enabled"]:
        sys.exit("the slot refused observation time")
state.update(serving_model=model_id, bundle_id=bundle["bundle_id"])
