"""
Practice: estimate, then check. Lab 01's arithmetic (estimate.py, percentiles.py,
05_littles_law.py): requests a second from product numbers, servers at peak, a percentile
computed numpy's default way, how many samples a percentile rests on, and Little's law.

Fill in the TODOs, then run the tests:
    pytest test_estimate_practice.py        (locally)
or press "Run tests" on the chapter page.
"""
import math

SECONDS_PER_DAY = 86_400


def peak_rps(daily_users, reads_per_user, writes_per_user, peak_factor):
    """Requests a second in the busiest hour: (reads + writes) per day spread over a day,
    times the peak factor (busiest hour ÷ daily average)."""
    return daily_users * (reads_per_user + writes_per_user) / SECONDS_PER_DAY * peak_factor


def servers_needed(peak, rps_per_server, headroom=0.3):
    """Servers to carry `peak` requests a second while keeping `headroom` of each one spare.
    Round up, and never fewer than 1."""
    return max(1, math.ceil(peak / (rps_per_server * (1 - headroom))))


def percentile(xs, q):
    """The q-th percentile (0-100), numpy's default ("linear") way: sort, find position
    h = (n - 1) * q / 100, and interpolate between the values on either side of it."""
    x = sorted(xs)
    h = (len(x) - 1) * q / 100
    lo, hi = math.floor(h), math.ceil(h)
    return x[lo] + (h - lo) * (x[hi] - x[lo])


def samples_above(n, q):
    """How many of n samples you expect above the q-th percentile."""
    return n * (1 - q / 100)


def min_n_bounded(q, conf=0.95):
    """The smallest sample size whose order-statistic interval for the q-th percentile has an
    upper end. The upper end exists once some sample is likely enough to land above the true
    percentile: P(at least one of n samples is above it) = 1 - p**n must reach 1 - (1 - conf)/2,
    where p = q / 100."""
    p = q / 100
    target = 1 - (1 - conf) / 2
    n = 1
    while 1 - p**n < target:
        n += 1
    return n


def littles_L(arrivals_per_s, time_in_system_s):
    """Little's law: requests in flight = arrival rate x time each one spends inside."""
    return arrivals_per_s * time_in_system_s
