"""Print every number the lesson quotes. Run: python3 show_numbers.py"""
import tail_sim as sim


def row(name: str, stats: dict) -> str:
    return f"{name:>8} | " + " | ".join(f"{sim.seconds_text(stats[k]):>7}" for k in ("average", "p50", "p95", "p99", "max"))


def main() -> None:
    w = sim.WORKLOAD
    n = len(w["gaps"])
    long_replies = sum(1 for r in w["replies"] if r >= sim.LONG_REPLY[0])
    print(f"{n} requests (seed {sim.SEED}); prompts {min(w['prompts'])} to {max(w['prompts'])} tokens; replies {min(w['replies'])} to {max(w['replies'])} tokens, "
          f"{long_replies} of {n} long (100 or more); mean reply {sim.mean(w['replies']):.1f} tokens; {sim.SLOTS} slots; "
          f"capacity {sim.capacity():.3f} requests a second")
    print()
    swept = sim.sweep()
    for measure in ("total", "wait"):
        print(f"{measure} time in seconds, on-schedule tester (columns: average, p50, p95, p99, slowest)")
        for rate in sim.RATES:
            print(row(f"{rate}/s", swept[rate][measure]))
        print()
    opening = swept[sim.OPENING_RATE]["total"]
    print("opening widget line:", sim.headline(opening, "total"))
    print("opening widget key:", sim.key_rows(opening))
    print()
    run = sim.serve(w, sim.OPENING_RATE)
    times = sim.totals(run)
    avg = sim.mean(times)
    print(f"at {sim.OPENING_RATE}/s total time: {sum(1 for t in times if t > avg)} of {n} requests take longer than the average; "
          f"{sum(1 for t in times if t <= avg)} take the average or less; "
          f"{sum(1 for t in times if t > sim.percentile(times, 95))} take more than p95; {sum(1 for t in times if t > sim.percentile(times, 99))} take more than p99")
    print()
    print("session chance (slow share, requests): 1 - (1 - share)^requests, independent waits")
    for share, k in ((0.05, 1), (0.05, 10), (0.05, 20), (0.01, 100)):
        print(f"  {share:.2f}, {k:3}: {sim.session_chance(share, k):.4f}")
    print()
    demo = sim.generator_demo()
    print(f"two testers, {sim.DEMO_RATE} requests a second, a {sim.PAUSE:g} s freeze at {sim.PAUSE_AT:g} s, {sim.CONNECTIONS} connections for the waiting tester")
    for name, result in demo.items():
        print(f"  {name}:")
        print("   wait  ", row("", result["wait"]).strip())
        print("   total ", row("", result["total"]).strip())
        print(f"   requests that waited over {sim.SLOW_WAIT:g} s for the first word: {result['slow']}")
    schedule = sim.serve(w, sim.DEMO_RATE, 0, sim.PAUSE)
    waiting = sim.serve(w, sim.DEMO_RATE, sim.CONNECTIONS, sim.PAUSE)
    late = lambda r: sum(1 for s, i in zip(r.sent, r.intended) if s > i)
    calm = late(sim.serve(w, sim.DEMO_RATE, sim.CONNECTIONS))
    print(f"  the waiting tester sent {late(waiting)} of {n} requests later than meant with the freeze and {calm} without it, so the freeze adds {late(waiting) - calm}; "
          f"the last request went at {max(waiting.sent):.1f} s against {max(schedule.sent):.1f} s")
    print(f"  requests sent while the server was frozen ({sim.PAUSE_AT:g} to {sim.PAUSE_AT + sim.PAUSE:g} s): on schedule {sum(1 for s in schedule.sent if sim.PAUSE_AT <= s < sim.PAUSE_AT + sim.PAUSE)}, "
          f"waiting {sum(1 for s in waiting.sent if sim.PAUSE_AT <= s < sim.PAUSE_AT + sim.PAUSE)}")
    print()
    ex = sim.pooled_example()
    print(f"averaging p99s: two servers, {ex['requests']:,} requests each, wait before the first word; quiet p99 {ex['quiet_p99']:.4f}, busy p99 {ex['busy_p99']:.4f}, "
          f"average of the two {ex['averaged']:.4f}, p99 of all {2 * ex['requests']:,} {ex['pooled']:.4f}")
    print()
    spread = sim.shuffle_spread()
    print(f"over the widget's {len(sim.REROLLS)} shuffles at {sim.OPENING_RATE}/s, total time: average {sim.seconds_text(spread['average'][0])} to {sim.seconds_text(spread['average'][1])} s, "
          f"p99 {sim.seconds_text(spread['p99'][0])} to {sim.seconds_text(spread['p99'][1])} s")
    print()
    print("what a percentile rests on: requests slower than p99 among n samples (nearest rank)")
    for count in (50, 100, 101, 200, 1000, 2000):
        rank = -(-99 * count // 100)
        print(f"  n {count:5}: p99 is the value at rank {rank}; {count - rank} slower")


if __name__ == "__main__":
    main()
