from conftest import register


def add_execution(api,comp,success):
    response=api.post("/api/v1/executions",json={"client_id":comp["client_id"],"operation":"extract","success":success,
      "composition_revision":comp["revision"],
      "error_kind":None if success else "bad_header","duration_ms":2.5,"calls":[
       {"spec_function":spec,"implementation_id":impl,"outcome":"ok" if success else "error"}
       for spec,impl in comp["implementations"].items()]})
    assert response.status_code == 201
    if not success:
        event=api.post("/api/v1/telemetry",json={"client_id":comp["client_id"],"execution_id":response.json()["execution_id"],
          "release_id":comp["release_id"],"composition_revision":comp["revision"],"event_type":"extraction_failure",
          "spec_function":"parse_header","implementation_id":comp["implementations"]["parse_header"],"message_code":"observable_failure","recent_calls":[
           {"spec_function":"parse_header","implementation_id":comp["implementations"]["parse_header"],"outcome":"error"}]})
        assert event.status_code == 201


def test_stats_identify_faulty_variant_and_keep_call_history(api,release):
    clients=[register(api,release,n) for n in range(24)]
    for c in clients:
        failed=c["implementations"]["parse_header"] == "header_bad"
        for _ in range(3): add_execution(api,c,not failed)
    stats={x["id"]:x for x in api.get("/api/v1/stats/implementations").json()}
    assert stats["header_bad"]["failure_rate"] == 1
    assert stats["header_a"]["failure_rate"] == 0
    assert stats["header_bad"]["infinite_relative_risk"] is True
    assert stats["header_bad"]["experimental"] is True
    assert stats["header_a"]["experimental"] is False
    events=api.get("/api/v1/telemetry?limit=2").json()
    assert len(events)==2 and events[0]["recent_calls"][0]["spec_function"] == "parse_header"
    summary=api.get(f"/api/v1/dashboard/summary?release_id={release['id']}").json()
    assert summary["clients"] == 24 and summary["telemetry_events"] == 36
    assert summary["theoretical_compositions"] == 4
    assert summary["latest_execution_at"].endswith("Z")


def test_pairwise_interaction_is_understandable(api,release):
    clients=[register(api,release,n) for n in range(40)]
    for c in clients:
        active=set(c["implementations"].values())
        failed={"header_bad","path_b"} <= active
        for _ in range(3): add_execution(api,c,not failed)
    pairs=api.get("/api/v1/stats/interactions?min_executions=3").json()
    target=next(p for p in pairs if {p["implementation_a"],p["implementation_b"]}=={"header_bad","path_b"})
    assert target["failure_rate"] == 1
    assert target["interaction_lift"] > 0


def test_validation_rejects_mismatched_attribution(api,release):
    client=register(api,release,1)
    response=api.post("/api/v1/telemetry",json={"client_id":client["client_id"],"event_type":"panic","spec_function":"parse_header"})
    assert response.status_code == 422
    response=api.post("/api/v1/telemetry",json={"client_id":client["client_id"],"release_id":client["release_id"],
      "composition_revision":client["revision"],"event_type":"panic","spec_function":"parse_header",
      "implementation_id":"not_active","recent_calls":[]})
    assert response.status_code == 422
    response=api.post("/api/v1/executions",json={"client_id":client["client_id"],"operation":"extract /private/file.zip","success":False})
    assert response.status_code == 422


def test_historical_composition_accepts_inflight_reports_and_validates_calls(api,release):
    clients=[register(api,release,n) for n in range(4)]
    old=next(c for c in clients if c["implementations"]["parse_header"]=="header_bad")
    api.put("/api/v1/implementations/header_bad/status",json={"status":"quarantined","reason":"test"}).raise_for_status()
    current=api.get(f"/api/v1/clients/{old['client_id']}/composition").json()
    assert current["revision"] == 2
    execution=api.post("/api/v1/executions",json={"client_id":old["client_id"],"composition_revision":old["revision"],
      "operation":"extract","success":False,"error_kind":"inflight","calls":[
       {"spec_function":"parse_header","implementation_id":"header_bad","outcome":"error"}]})
    assert execution.status_code == 201
    event=api.post("/api/v1/telemetry",json={"client_id":old["client_id"],"release_id":old["release_id"],
      "composition_revision":old["revision"],"execution_id":execution.json()["execution_id"],
      "event_type":"extraction_failure","spec_function":"parse_header","implementation_id":"header_bad",
      "recent_calls":[{"spec_function":"parse_header","implementation_id":"header_bad","outcome":"error"}]})
    assert event.status_code == 201
    mismatch=api.post("/api/v1/executions",json={"client_id":old["client_id"],"composition_revision":current["revision"],
      "operation":"extract","success":False,"calls":[
       {"spec_function":"parse_header","implementation_id":"header_bad","outcome":"error"}]})
    assert mismatch.status_code == 422


def test_dashboard_is_release_scoped_and_quarantine_cutoff_is_exact(api,release):
    second=api.post("/api/v1/releases",json={"application":"zipdiv","version":"2.0.0","spec_functions":[
      {"name":"parse_header","implementations":[{"id":"v2_bad","name":"bad"},{"id":"v2_good","name":"good"}]}]}).json()
    clients=[]
    for n in range(4):
        response=api.post("/api/v1/clients",json={"release_id":second["id"],"installation_id":f"v2-{n}","strategy":"balanced"})
        clients.append(response.json())
    bad=next(c for c in clients if c["implementations"]["parse_header"]=="v2_bad")
    add_execution(api,bad,False)
    api.put("/api/v1/implementations/v2_bad/status",json={"status":"quarantined","reason":"test"}).raise_for_status()
    replacement=api.get(f"/api/v1/clients/{bad['client_id']}/composition").json()
    add_execution(api,replacement,True)

    first_summary=api.get("/api/v1/dashboard/summary",params={"release_id":release["id"]}).json()
    assert first_summary["executions"] == 0
    assert first_summary["telemetry_events"] == 0
    assert first_summary["quarantined"] == []
    assert {x["implementation_id"] for x in first_summary["active_distribution"]} <= {
        "header_a","header_bad","path_a","path_b"}

    second_summary=api.get("/api/v1/dashboard/summary",params={"release_id":second["id"]}).json()
    assert second_summary["executions"] == 2
    assert second_summary["telemetry_events"] == 1
    assert second_summary["theoretical_compositions"] == 1
    assert second_summary["observed_compositions"] == 1
    assert [x["id"] for x in second_summary["quarantined"]] == ["v2_bad"]
    effect=second_summary["quarantine_effects"][0]
    assert effect["before_executions"] == 1 and effect["before_failure_rate"] == 1
    assert effect["after_executions"] == 1 and effect["after_failure_rate"] == 0
    sequence=second_summary["quarantine_sequence"]
    assert [(stage["executions"],stage["healthy_rate"]) for stage in sequence] == [(1,0),(1,1)]
    assert sequence[1]["implementation_id"] == "v2_bad"
    assert api.get("/api/v1/telemetry",params={"release_id":release["id"]}).json() == []
