#!/usr/bin/env python3
"""Calculate a two-sided Wilson score interval for a binomial proportion.

Uses only the Python standard library. No continuity correction is applied.
"""

from __future__ import annotations

import argparse
import math
from statistics import NormalDist


def wilson_interval(correct: int, total: int, confidence: float = 0.95) -> tuple[float, float]:
    """Return lower and upper Wilson limits as proportions in [0, 1]."""
    if total <= 0:
        raise ValueError("total must be greater than zero")
    if correct < 0 or correct > total:
        raise ValueError("correct must be between zero and total")
    if not 0 < confidence < 1:
        raise ValueError("confidence must be between zero and one")

    observed = correct / total
    z = NormalDist().inv_cdf(0.5 + confidence / 2)
    z2 = z * z
    denominator = 1 + z2 / total
    centre = (observed + z2 / (2 * total)) / denominator
    margin = (
        z
        * math.sqrt(observed * (1 - observed) / total + z2 / (4 * total * total))
        / denominator
    )
    return max(0.0, centre - margin), min(1.0, centre + margin)


def main() -> None:
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("correct", type=int)
    parser.add_argument("total", type=int)
    parser.add_argument("--confidence", type=float, default=0.95)
    args = parser.parse_args()

    low, high = wilson_interval(args.correct, args.total, args.confidence)
    observed = args.correct / args.total
    print(f"observed={observed * 100:.1f}%")
    print(
        f"wilson_{args.confidence * 100:g}%="
        f"{low * 100:.1f}% to {high * 100:.1f}%"
    )


if __name__ == "__main__":
    main()
