using System.Numerics;
using LeetCode.Logic;

namespace LeetCode.Tests;

public class FibonacciNumsTests
{
    private readonly FibonacciNums _sut = new ();

    [Theory]
    [InlineData(0, "0")]
    [InlineData(1, "1")]
    [InlineData(2, "1")]
    [InlineData(3, "2")]
    [InlineData(10, "55")]
    [InlineData(50, "12586269025")]
    [InlineData(100, "354224848179261915075")]
    public void GetNthFibonacci_ShouldReturnCorrectValue(int n, string expected)
    {
        // Arrange
        var fib = new FibonacciNums();
        var expectedValue = BigInteger.Parse(expected);

        // Act
        var result = fib.GetNthFibonacci(n);

        // Assert
        Assert.Equal(expectedValue, result);
    }
    
    
    [Theory]
    [InlineData("10", "50", new [] { "13", "21", "34" })]              // Range between non-Fibonacci numbers
    [InlineData("0", "5", new [] { "0", "1", "1", "2", "3", "5" })]         // Starting from zero
    [InlineData("8", "21", new [] { "8", "13", "21" })]               // Boundaries are Fibonacci numbers
    [InlineData("100", "200", new [] { "144" })]                  // Range with only one Fibonacci number
    [InlineData("4", "7", new[] { "5" })]                        // Range with one number, boundaries are not Fib
    [InlineData("12200160415121876738", "12200160415121876739", new[] { "12200160415121876738" })] // The 93rd Fib (Overflows long)
    public void GetFibonacciInRange(string minStr, string maxStr, string[] expectedStr)
    {
        // Arrange 
        BigInteger min = BigInteger.Parse(minStr);
        BigInteger max = BigInteger.Parse(maxStr);
        var expected = expectedStr.Select(BigInteger.Parse).ToArray();
        
        // Act
        var actual = _sut.GetFibonacciInRange(min, max);

        // Assert
        Assert.Equal(expected, actual);
    }
    
    
    [Theory]
    [InlineData(14, new long[] { 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233 })]
    [InlineData(1, new long[] { 0,  })]
    [InlineData(2, new long[] { 0, 1 })]
    [InlineData(3, new long[] { 0, 1, 1 })]
    [InlineData(0, new long[] { })]
    public void FirstXNumbers(int n, long[] expected)
    {
        var result = _sut.FirstXNumbers(n);
        
        Assert.Equal(expected, result);
    }

    [Theory]
    [InlineData(0, true)]
    [InlineData(1, true)]
    [InlineData(2, true)]
    [InlineData(3, true)]
    [InlineData(5, true)]
    [InlineData(8, true)]
    [InlineData(13, true)]
    [InlineData(21, true)]
    [InlineData(34, true)]
    [InlineData(55, true)]
    [InlineData(89, true)]
    [InlineData(144, true)]
    [InlineData(4, false)]
    [InlineData(6, false)]
    [InlineData(7, false)]
    [InlineData(9, false)]
    [InlineData(10, false)]
    [InlineData(11, false)]
    [InlineData(12, false)]
    private void Fibonacci(int num, bool expected)
    {
        var result = _sut.IsFibonacci(num);
        
        Assert.Equal(expected, result);
    }

}