using YatzyLibrary;

namespace YatzyTest;

public class YatzyCheckersTests
{
    YatzyCheckers yatzyCheckers = new YatzyCheckers();

    [Theory]
    [InlineData(new int[] { 1, 2, 4, 1, 4 }, 1, true, 2)]
    [InlineData(new int[] { 1, 2, 4, 1, 4 }, 4, true, 8)]
    [InlineData(new int[] { 2, 3, 4, 5, 6 }, 1, true, 0)]
    [InlineData(new int[] { 1, 1, 1, 1, 1 }, 1, true, 5)]
    [InlineData(new int[] { 1, 2, 3, 4, 5 }, 1, true, 1)]
    [InlineData(new int[] { 6, 6, 6, 6, 6 }, 6, true, 30)]
    public void SingleThingy(int[] dices, int valueToCheck, bool expectedSuccess, int expectedValue)
    {
        var result = yatzyCheckers.SingleThingy(dices.ToList(), valueToCheck);
        Assert.Equal(new CheckOutput(expectedSuccess, expectedValue), result);
    }

    [Theory]
    [InlineData(new int[] { 1, 2, 4, 1, 4 }, 1, true, 8)]
    [InlineData(new int[] { 1, 2, 4, 1, 4 }, 2, true, 10)]
    [InlineData(new int[] { 1, 2, 3, 4, 5 }, 1, false, 0)]
    [InlineData(new int[] { 4, 4, 4, 2, 3 }, 1, true, 8)]
    [InlineData(new int[] { 2, 2, 6, 6, 1 }, 1, true, 12)]
    [InlineData(new int[] { 2, 2, 6, 6, 1 }, 2, true, 16)]
    [InlineData(new int[] { 5, 5, 5, 5, 2 }, 1, true, 10)]
    public void PairChecker(int[] dices, int pairs, bool expectedSuccess, int expectedValue)
    {
        var result = yatzyCheckers.PairChecker(dices.ToList(), pairs);
        Assert.Equal(new CheckOutput(expectedSuccess, expectedValue), result);
    }

    [Theory]
    [InlineData(new int[] { 6, 6, 6, 6, 4 }, 3, true, 18)]
    [InlineData(new int[] { 6, 6, 6, 6, 4 }, 4, true, 24)]
    [InlineData(new int[] { 1, 2, 3, 4, 5 }, 3, false, 0)]
    [InlineData(new int[] { 1, 1, 1, 2, 3 }, 4, false, 0)]
    [InlineData(new int[] { 3, 3, 3, 3, 3 }, 3, true, 9)]
    [InlineData(new int[] { 3, 3, 3, 3, 3 }, 4, true, 12)]
    [InlineData(new int[] { 2, 2, 2, 4, 5 }, 3, true, 6)]
    [InlineData(new int[] { 6, 6, 6, 6, 1 }, 4, true, 24)]
    public void SameNumberChecker(int[] dices, int pairs, bool expectedSuccess, int expectedValue)
    {
        var result = yatzyCheckers.SameNumberChecker(dices.ToList(), pairs);
        Assert.Equal(new CheckOutput(expectedSuccess, expectedValue), result);
    }

    [Theory]
    [InlineData(new int[] { 1, 2, 3, 1, 4 }, "small", true, 15)]
    [InlineData(new int[] { 1, 2, 3, 4, 5 }, "large", true, 20)]
    [InlineData(new int[] { 1, 2, 3, 4, 6 }, "small", true, 15)]
    [InlineData(new int[] { 2, 3, 4, 5, 1 }, "small", true, 15)]
    [InlineData(new int[] { 3, 4, 5, 6, 1 }, "small", true, 15)]
    [InlineData(new int[] { 2, 3, 4, 5, 6 }, "large", true, 20)]
    [InlineData(new int[] { 1, 3, 4, 5, 6 }, "small", false, 0)]
    [InlineData(new int[] { 1, 3, 4, 5, 6 }, "large", false, 0)]
    [InlineData(new int[] { 1, 2, 2, 3, 4 }, "small", true, 15)]
    [InlineData(new int[] { 1, 2, 3, 4, 5 }, "SMALL", true, 15)]
    [InlineData(new int[] { 1, 2, 3, 4, 5 }, "LARGE", true, 20)]
    public void StraightChecker(int[] dices, string type, bool expectedSuccess, int expectedValue)
    {
        var result = yatzyCheckers.StraightChecker(dices.ToList(), type);
        Assert.Equal(new CheckOutput(expectedSuccess, expectedValue), result);
    }

    [Theory]
    [InlineData(new int[] { 3, 3, 3, 5, 5 }, true, 19)]
    [InlineData(new int[] { 6, 6, 6, 6, 4 }, false, 0)]
    [InlineData(new int[] { 2, 2, 4, 4, 1 }, false, 0)]
    [InlineData(new int[] { 1, 1, 1, 2, 2 }, true, 7)]
    [InlineData(new int[] { 6, 6, 4, 4, 4 }, true, 24)]
    [InlineData(new int[] { 1, 1, 2, 2, 3 }, false, 0)]
    [InlineData(new int[] { 3, 3, 3, 3, 3 }, false, 0)]
    [InlineData(new int[] { 1, 2, 3, 4, 5 }, false, 0)]
    [InlineData(new int[] { 1, 1, 2, 3, 4 }, false, 0)]
    public void FullHouse(int[] dices, bool expectedSuccess, int expectedValue)
    {
        var result = yatzyCheckers.FullHouse(dices.ToList());
        Assert.Equal(new CheckOutput(expectedSuccess, expectedValue), result);
    }

    [Theory]
    [InlineData(new int[] { 6, 6, 6, 6, 6 }, true, 50)]
    [InlineData(new int[] { 5, 5, 5, 5, 3 }, false, 0)]
    [InlineData(new int[] { 1, 1, 1, 1, 1 }, true, 50)]
    [InlineData(new int[] { 1, 2, 3, 4, 5 }, false, 0)]
    [InlineData(new int[] { 2, 2, 2, 2, 3 }, false, 0)]
    [InlineData(new int[] { 2, 2, 2, 2, 2 }, true, 50)]
    [InlineData(new int[] { 3, 3, 3, 3, 3 }, true, 50)]
    [InlineData(new int[] { 4, 4, 4, 4, 4 }, true, 50)]
    public void Yatzy(int[] dices, bool expectedSuccess, int expectedValue)
    {
        var result = yatzyCheckers.Yatzy(dices.ToList());
        Assert.Equal(new CheckOutput(expectedSuccess, expectedValue), result);
    }

    [Theory]
    [InlineData(new int[] { 1, 2, 3, 4, 5 }, true, 15)]
    [InlineData(new int[] { 6, 6, 6, 6, 6 }, true, 30)]
    [InlineData(new int[] { 1, 1, 1, 1, 1 }, true, 5)]
    [InlineData(new int[] { 2, 3, 4, 5, 6 }, true, 20)]
    public void Chance(int[] dices, bool expectedSuccess, int expectedValue)
    {
        var result = yatzyCheckers.Chance(dices.ToList());
        Assert.Equal(new CheckOutput(expectedSuccess, expectedValue), result);
    }

    [Theory]
    [InlineData(new int[] { 1, 2, 2, 3, 3, 3, 4 }, new int[] { 1, 2, 3, 4 })]
    [InlineData(new int[] { 1, 2, 3, 4, 5 }, new int[] { 1, 2, 3, 4, 5 })]
    [InlineData(new int[] { }, new int[] { })]
    [InlineData(new int[] { 5 }, new int[] { 5 })]
    [InlineData(new int[] { 3, 3, 3, 3, 3 }, new int[] { 3 })]
    public void RemoveDuplicats_Tests(int[] input, int[] expected)
    {
        var result = yatzyCheckers.RemoveDuplicats(input.ToList());
        Assert.Equal(expected.ToList(), result);
    }

    // Keep some edge case tests as individual facts for clarity
    [Fact]
    public void PairChecker_NoValidPairs_ReturnsFalse()
    {
        var noPairs = new List<int>() { 1, 2, 3, 4, 5 };
        var result = yatzyCheckers.PairChecker(noPairs, 1);
        Assert.Equal(new CheckOutput(false, 0), result);
    }

    [Fact]
    public void SameNumberChecker_FiveOfAKind_WorksForBothThreeAndFour()
    {
        var fiveOfAKind = new List<int>() { 3, 3, 3, 3, 3 };
        
        var threeResult = yatzyCheckers.SameNumberChecker(new List<int>(fiveOfAKind), 3);
        Assert.Equal(new CheckOutput(true, 9), threeResult);
        
        var fourResult = yatzyCheckers.SameNumberChecker(new List<int>(fiveOfAKind), 4);
        Assert.Equal(new CheckOutput(true, 12), fourResult);
    }

    [Fact]
    public void AllYatzyValues_ShouldReturn50Points()
    {
        for (int i = 1; i <= 6; i++)
        {
            var yatzy = new List<int>() { i, i, i, i, i };
            var result = yatzyCheckers.Yatzy(yatzy);
            Assert.Equal(new CheckOutput(true, 50), result);
        }
    }
}
