#!/usr/bin/env python3
"""Fibonacci utilities: a memoised recursive form and an iterative generator."""
from __future__ import annotations

from dataclasses import dataclass
from functools import lru_cache


@lru_cache(maxsize=None)
def fib(n: int) -> int:
    """Return the n-th Fibonacci number (0-indexed)."""
    if n < 0:
        raise ValueError("n must be non-negative")
    if n < 2:
        return n
    return fib(n - 1) + fib(n - 2)


def fib_sequence(count: int):
    """Yield the first `count` Fibonacci numbers, iteratively."""
    a, b = 0, 1
    for _ in range(count):
        yield a
        a, b = b, a + b


@dataclass(frozen=True)
class Report:
    count: int
    total: int

    def average(self) -> float:
        return self.total / self.count if self.count else 0.0


def main() -> None:
    seq = list(fib_sequence(10))
    report = Report(count=len(seq), total=sum(seq))
    print(f"sequence: {seq}")
    print(f"fib(20) = {fib(20)}")
    print(f"average of first {report.count}: {report.average():.1f}")


if __name__ == "__main__":
    main()
