"""
Unit tests for the Fibonacci function.

Comprehensive test suite covering edge cases, basic cases, and input validation.
"""

import pytest
from fibonacci import fibonacci


class TestFibonacciBasics:
    """Test basic Fibonacci sequence values."""

    def test_fibonacci_zero(self):
        """Test that fibonacci(0) returns 0."""
        assert fibonacci(0) == 0

    def test_fibonacci_one(self):
        """Test that fibonacci(1) returns 1."""
        assert fibonacci(1) == 1

    def test_fibonacci_two(self):
        """Test that fibonacci(2) returns 1."""
        assert fibonacci(2) == 1

    def test_fibonacci_five(self):
        """Test that fibonacci(5) returns 5."""
        assert fibonacci(5) == 5

    def test_fibonacci_ten(self):
        """Test that fibonacci(10) returns 55."""
        assert fibonacci(10) == 55


class TestFibonacciSequence:
    """Test complete Fibonacci sequence values."""

    def test_fibonacci_sequence(self):
        """Test a known sequence of Fibonacci numbers."""
        expected = [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
        for n, expected_value in enumerate(expected):
            assert fibonacci(n) == expected_value, f"fibonacci({n}) should be {expected_value}"


class TestFibonacciEdgeCases:
    """Test edge cases and boundary conditions."""

    def test_fibonacci_negative_input(self):
        """Test that fibonacci returns None for negative input."""
        assert fibonacci(-1) is None
        assert fibonacci(-5) is None
        assert fibonacci(-100) is None

    def test_fibonacci_large_number(self):
        """Test Fibonacci with a larger number."""
        # fibonacci(20) = 6765
        assert fibonacci(20) == 6765

    def test_fibonacci_very_large_number(self):
        """Test Fibonacci with a very large number."""
        # fibonacci(30) = 832040
        assert fibonacci(30) == 832040


class TestFibonacciProperties:
    """Test mathematical properties of Fibonacci numbers."""

    def test_fibonacci_sum_property(self):
        """Test that sum of first n Fibonacci numbers equals fibonacci(n+2) - 1."""
        # Sum of fibonacci(0) to fibonacci(4) should equal fibonacci(6) - 1
        fib_sum = sum(fibonacci(i) for i in range(5))
        assert fib_sum == fibonacci(6) - 1

    def test_fibonacci_golden_ratio_approximation(self):
        """Test that ratio of consecutive Fibonacci numbers approaches golden ratio."""
        # For large n, fibonacci(n) / fibonacci(n-1) approaches phi (1.618...)
        phi = (1 + 5 ** 0.5) / 2
        ratio = fibonacci(15) / fibonacci(14)
        # Allow some tolerance for approximation
        assert abs(ratio - phi) < 0.01
