from collections.abc import Iterator
from datetime import datetime

import argparse
import csv
import math
import random
import sys


def rand_n() -> int:
    return random.randint(1, sys.maxsize)


def generate_pi_estimates(max_power_ten: int) -> Iterator[tuple]:
    notify_at = 1
    trial_num = 0
    coprime_count = 0
    start = datetime.now()
    while trial_num < 10**max_power_ten:
        if math.gcd(rand_n(), rand_n()) == 1:
            coprime_count += 1
        trial_num += 1
        if trial_num == notify_at:
            notify_at *= 10
            duration = datetime.now() - start
            if coprime_count == 0:
                pi_estimate = 0  # Unlikely, but...
            else:
                pi_estimate = math.sqrt((6 * trial_num) / coprime_count)
            error = 100 * abs(math.pi - pi_estimate) / math.pi
            yield (
                trial_num,
                coprime_count,
                pi_estimate,
                error,
                duration.total_seconds(),
            )


def main(argv):
    ap = argparse.ArgumentParser()
    ap.add_argument("-m", "--max-power-of-ten", default=9, type=int, dest="max_power")
    args = ap.parse_args(argv)

    if args.max_power < 0:
        raise Exception("-m/--max-power should be non-negative.")

    writer = csv.writer(sys.stdout)
    writer.writerow(
        ("Trials", "Coprime Pairs", "Estimated Pi", "Error Percentage", "Duration (s)")
    )

    for result in generate_pi_estimates(max_power_ten=args.max_power):
        writer.writerow(result)


if __name__ == "__main__":
    main(sys.argv[1:])
