#!/usr/bin/env python3
"""Evaluate one B2B advertising-platform pilot record without network access."""
import json, re, sys
from datetime import date, datetime
from pathlib import Path

UNKNOWN = {"", "unknown"}
ROUTE_FOR_MOMENT = {
    "active_search": "search_intent",
    "professional_identity": "professional_social",
    "interest_discovery": "interest_discovery",
    "community_context": "community_context",
}
REQUESTS = {
    "record": ("REQ_RECORD_SHAPE", "Return one top-level b2b_platform_decision/v1 object; do not wrap it or replace required objects with scalars."),
    "buyer": ("REQ_BUYER", "Supply the named buyer roles, company scope and geography with an owner and evidence reference."),
    "buying_moment": ("REQ_BUYING_MOMENT", "Choose one supported buying moment and supply the dated evidence that supports it."),
    "offer": ("REQ_OFFER", "Supply the approved offer, format and owner."),
    "destination": ("REQ_DESTINATION", "Provide the approved destination, owner and successful test receipt."),
    "consent": ("REQ_CONSENT", "Provide the responsible owner, approval state and evidence for the proposed data and audience use."),
    "follow_up": ("REQ_FOLLOW_UP", "Provide the CRM object, route owner and a successful controlled routing receipt."),
    "measurement": ("REQ_MEASUREMENT", "Name the source, platform, destination and CRM receipts, cutoff and review deadline."),
    "candidates": ("REQ_CANDIDATES", "Supply at least one documented candidate for the required distribution route and select exactly one primary candidate."),
    "account_observation": ("REQ_ACCOUNT_OBSERVATION", "Read back current target-account access and usable audience or query availability for the selected route."),
    "pilot": ("REQ_PILOT_CONTRACT", "Supply the approved budget, dates, learning question, audience rules, operating owner, reviewer and stop, repair and expansion conditions."),
    "action_authorization": ("REQ_ACTION_AUTHORIZATION", "Record whether an authorized owner approved the external campaign action; decision readiness alone is not launch authorization."),
    "post_launch": ("REQ_POST_LAUNCH_RECEIPTS", "Read back the required post-launch receipts for the same campaign identity and cutoff."),
}

def absent(v):
    return not isinstance(v, str) or v.strip().lower() in UNKNOWN

def hold(state, detail=None, disposition="HOLD"):
    rid, request = REQUESTS[state]
    return {"disposition": disposition, "first_broken_state": state, "request_id": rid, "request": request, "detail": detail or ""}

def valid_date(value):
    if not isinstance(value, str) or not re.fullmatch(r"\d{4}-\d{2}-\d{2}", value):
        return None
    try:
        return date.fromisoformat(value)
    except ValueError:
        return None

def evaluate(record):
    if isinstance(record, dict) and isinstance(record.get("record"), dict) and set(record).issubset({"record", "evaluation"}):
        record = record["record"]
    if not isinstance(record, dict):
        return hold("record")
    if record.get("schema_version") != "b2b_platform_decision/v1" or absent(record.get("scenario_id")) or not isinstance(record.get("fictional_fixture"), bool) or record.get("phase") not in {"planning", "post_launch"}:
        return hold("record", "schema_version")
    for key in ("scope", "buyer", "buying_moment", "offer", "destination", "consent", "follow_up", "measurement", "pilot", "action_authorization"):
        if not isinstance(record.get(key), dict):
            return hold("record", key)
    scope = record["scope"]

    buyer = record["buyer"]
    if (not isinstance(buyer.get("roles"), list) or not buyer["roles"] or
        any(absent(x) for x in buyer["roles"]) or absent(buyer.get("company_scope")) or
        absent(buyer.get("geography")) or absent(buyer.get("owner")) or absent(buyer.get("evidence_ref"))):
        return hold("buyer")

    moment = record["buying_moment"]
    mode = moment.get("mode")
    if mode not in ROUTE_FOR_MOMENT or absent(moment.get("evidence_ref")) or absent(moment.get("owner")):
        return hold("buying_moment")

    offer = record["offer"]
    if absent(offer.get("name")) or absent(offer.get("format")) or absent(offer.get("owner")) or offer.get("approved") is not True:
        return hold("offer")

    destination = record["destination"]
    if destination.get("kind") not in {"website", "native_form"} or absent(destination.get("location")) or absent(destination.get("owner")) or absent(destination.get("test_receipt")):
        return hold("destination")

    consent = record["consent"]
    if consent.get("status") != "approved" or absent(consent.get("owner")) or absent(consent.get("evidence_ref")):
        return hold("consent")

    follow = record["follow_up"]
    if absent(follow.get("crm_object")) or absent(follow.get("owner")) or absent(follow.get("route_receipt")):
        return hold("follow_up")

    measurement = record["measurement"]
    expected = measurement.get("expected_receipts")
    if (not isinstance(expected, dict) or any(not isinstance(expected.get(x), dict) or absent(expected[x].get("name")) or absent(expected[x].get("unit")) for x in ("source", "platform", "destination", "crm")) or
        absent(measurement.get("qualified_unit")) or absent(measurement.get("cutoff")) or absent(measurement.get("review_deadline"))):
        return hold("measurement")
    if measurement.get("cutoff") != scope.get("cutoff"):
        return hold("measurement", "measurement.cutoff")

    candidates = record.get("candidates")
    if not isinstance(candidates, list) or not candidates or any(not isinstance(c, dict) for c in candidates):
        return hold("candidates")
    ids = [c.get("id") for c in candidates]
    if any(absent(x) for x in ids) or len(set(ids)) != len(ids):
        return hold("candidates", "candidate IDs must be unique")
    selected_id = record.get("selected_candidate_id")
    selected = [c for c in candidates if c.get("id") == selected_id]
    if len(selected) != 1:
        return hold("candidates", "select exactly one candidate")
    selected = selected[0]
    if selected.get("route") != ROUTE_FOR_MOMENT[mode]:
        return hold("candidates", "selected route does not match the evidenced buying moment")
    documented = selected.get("documented_capability")
    if not isinstance(documented, dict) or documented.get("state") != "documented" or absent(documented.get("evidence_ref")):
        return hold("candidates", "selected route lacks documented capability evidence")
    if record.get("secondary_route") != "HOLD" or not isinstance(record.get("change_conditions"), list) or not record["change_conditions"] or any(absent(x) for x in record["change_conditions"]):
        return hold("candidates", "secondary route must be HOLD with at least one change condition")
    observed = selected.get("account_observation")
    if (any(absent(scope.get(x)) for x in ("platform_account_id", "campaign_id", "audience_or_query_unit", "cutoff")) or
        not isinstance(observed, dict) or observed.get("state") != "observed" or
        any(absent(observed.get(x)) for x in ("evidence_ref", "observed_at", "platform_account_id", "unit", "cutoff", "sufficiency_reason")) or
        not isinstance(observed.get("value"), (int, float)) or isinstance(observed.get("value"), bool) or observed["value"] <= 0 or observed.get("usable") is not True or
        observed.get("platform_account_id") != scope["platform_account_id"] or observed.get("unit") != scope["audience_or_query_unit"] or observed.get("cutoff") != scope["cutoff"]):
        return hold("account_observation")

    pilot = record["pilot"]
    budget = pilot.get("budget")
    dates = pilot.get("date_range")
    capacity = pilot.get("operator_capacity")
    if not isinstance(budget, dict): return hold("pilot", "pilot.budget")
    if not isinstance(budget.get("amount"), (int, float)) or isinstance(budget.get("amount"), bool) or budget["amount"] <= 0: return hold("pilot", "pilot.budget.amount")
    for key in ("currency", "owner"):
        if absent(budget.get(key)): return hold("pilot", f"pilot.budget.{key}")
    if not isinstance(dates, dict): return hold("pilot", "pilot.date_range")
    start, end = valid_date(dates.get("start")), valid_date(dates.get("end"))
    if start is None: return hold("pilot", "pilot.date_range.start")
    if end is None or end < start: return hold("pilot", "pilot.date_range.end")
    if absent(pilot.get("learning_question")): return hold("pilot", "pilot.learning_question")
    for key in ("inclusion_rules", "exclusion_rules"):
        value=pilot.get(key)
        if not isinstance(value, list) or not value or any(absent(x) for x in value): return hold("pilot", f"pilot.{key}")
    if not isinstance(capacity, dict): return hold("pilot", "pilot.operator_capacity")
    if capacity.get("status") != "confirmed": return hold("pilot", "pilot.operator_capacity.status")
    for key in ("owner", "evidence_ref"):
        if absent(capacity.get(key)): return hold("pilot", f"pilot.operator_capacity.{key}")
    review_date=valid_date(pilot.get("review_date"))
    if review_date is None or review_date < end: return hold("pilot", "pilot.review_date")
    for key in ("reviewer", "stop_rule", "repair_rule", "expansion_rule", "decision_owner", "selection_rationale"):
        if absent(pilot.get(key)): return hold("pilot", f"pilot.{key}")
    authorization = record["action_authorization"]
    if authorization.get("status") not in {"not_authorized", "authorized"} or absent(authorization.get("owner")) or absent(authorization.get("evidence_ref")):
        return hold("action_authorization")

    if record.get("phase") == "post_launch":
        observed_receipts = measurement.get("observed_receipts")
        if not isinstance(observed_receipts, dict):
            return hold("post_launch", disposition="REPAIR_REQUIRED")
        for name in ("source", "platform", "destination", "crm"):
            receipt = observed_receipts.get(name)
            if (not isinstance(receipt, dict) or receipt.get("state") != "observed" or
                any(absent(receipt.get(x)) for x in ("evidence_ref", "platform_account_id", "campaign_id", "cutoff", "expectation_name", "unit")) or
                receipt.get("platform_account_id") != scope["platform_account_id"] or receipt.get("campaign_id") != scope["campaign_id"] or receipt.get("cutoff") != scope["cutoff"]):
                return hold("post_launch", detail=name, disposition="REPAIR_REQUIRED")
            if receipt["expectation_name"] != expected[name]["name"] or receipt["unit"] != expected[name]["unit"]:
                return hold("post_launch", detail=name, disposition="REPAIR_REQUIRED")
        disposition = "VERIFIED"
    else:
        disposition = "PILOT_READY"
    return {
        "disposition": disposition,
        "first_broken_state": "complete",
        "request_id": "NONE",
        "request": "",
        "selected_candidate_id": selected_id,
        "selected_route": selected["route"],
        "secondary_route": record.get("secondary_route", "HOLD"),
        "change_conditions": record.get("change_conditions", []),
        "launch_disposition": "AUTHORIZED_FOR_OPERATOR_ACTION" if authorization["status"] == "authorized" else "NOT_AUTHORIZED",
    }

def main():
    if len(sys.argv) != 2:
        raise SystemExit("usage: b2b-platform-checker.py RECORD.json")
    result = evaluate(json.loads(Path(sys.argv[1]).read_text()))
    print(json.dumps(result, indent=2))
    raise SystemExit(0 if result["first_broken_state"] == "complete" else 2)

if __name__ == "__main__":
    main()
