"""Impressions vs members reached: exact unique viewers vs the fast approximate count (dcount, HyperLogLog-style).

Sends 60 s of views at 5,000/sec from a pool of 200,000 members, then compares per post and in total:
  exact   = count of distinct (post, viewer) pairs
  approx  = dcount(viewer_id) at accuracy level 1 (default) and 4 (most accurate)
Output: unique_results.json
"""
import json, subprocess, sys, time
from kql import run

tag = f"uniq-{int(time.time())}"
out = subprocess.run([sys.executable, "producer.py", "--rate", "5000", "--seconds", "60", "--viewers", "200000", "--run", tag],
                     capture_output=True, text=True).stdout.strip().splitlines()[-1]
sent = json.loads(out)
time.sleep(60)
q = f"""PostViews | where run == '{tag}'
| summarize impressions = count(), exact = dcount(viewer_id, 4), approx1 = dcount(viewer_id, 1), approx4 = dcount(viewer_id, 4) by post_id
| top 20 by impressions"""
# exact distinct per post, without approximation
exact = {r["post_id"]: r["n"] for r in run(f"PostViews | where run == '{tag}' | distinct post_id, viewer_id | summarize n = count() by post_id")[0]}
rows, _ = run(q)
for r in rows:
    r["exact"] = exact[r["post_id"]]
    r["err1_pct"] = round(100 * (r["approx1"] - r["exact"]) / r["exact"], 2)
    r["err4_pct"] = round(100 * (r["approx4"] - r["exact"]) / r["exact"], 2)
tot_exact = run(f"PostViews | where run == '{tag}' | distinct viewer_id | count")[0][0]["Count"]
tot = run(f"PostViews | where run == '{tag}' | summarize impressions = count(), a1 = dcount(viewer_id, 1), a4 = dcount(viewer_id, 4)")[0][0]
t_exact = run(f"PostViews | where run == '{tag}' | distinct post_id, viewer_id | summarize n = count() by post_id")[1]
t_approx = run(f"PostViews | where run == '{tag}' | summarize n = dcount(viewer_id, 1) by post_id")[1]
res = {"run": tag, "sent": sent, "total": {"impressions": tot["impressions"], "exact_unique": tot_exact,
       "approx1": tot["a1"], "approx4": tot["a4"],
       "err1_pct": round(100 * (tot["a1"] - tot_exact) / tot_exact, 2), "err4_pct": round(100 * (tot["a4"] - tot_exact) / tot_exact, 2)},
       "query_ms": {"exact_per_post": round(t_exact), "approx_per_post": round(t_approx)},
       "top_posts": rows}
json.dump(res, open("unique_results.json", "w"), indent=1)
print(json.dumps({k: v for k, v in res.items() if k != "top_posts"}, indent=1))
print("worst per-post error, accuracy 1:", max(abs(r["err1_pct"]) for r in rows), "% | accuracy 4:", max(abs(r["err4_pct"]) for r in rows), "%")
