﻿using System.Linq;

using FluentAssertions;
using Xunit;
using static Epic.Numbers.NumbersUtility;

namespace Epic.Numbers.Tests
{
    public class NumberRangeTests
    {
        [Fact]
        public void NumbersInANumberRange_Int_NonStrict_Strict()
        {
            var range = Range(3, 5);
            range.Numbers().Should().ContainInOrder(3, 4);
        }

        [Fact]
        public void NumbersInANumberRange_Int_Strict_Strict()
        {
            var range = Range(3, 5, true, true);
            range.Numbers().Should().ContainInOrder(4);
        }

        [Fact]
        public void NumbersInANumberRange_Int_Strict_NonStrict()
        {
            var range = Range(3, 5, true, false);
            range.Numbers().Should().ContainInOrder(4, 5);
        }

        [Fact]
        public void NumbersInANumberRange_Int_NonStrict_NonStrict()
        {
            var range = Range(3, 5, false, false);
            range.Numbers().Should().ContainInOrder(3, 4, 5);
        }

        [Fact]
        public void IntersectionCount()
        {
            var ranges = new[] { Range(0, 5), Range(1, 4) };
            var intersectionCounts = ranges.IntersectionCount().ToList();
            intersectionCounts[0].Should().Be(new NumberRangeIntersectionCount<int>(new[] { ranges[0] }, Range(0, 1)));
            intersectionCounts[1].Should().Be(new NumberRangeIntersectionCount<int>(new[] { ranges[0], ranges[1] }, Range(1, 4)));
            intersectionCounts[2].Should().Be(new NumberRangeIntersectionCount<int>(new[] { ranges[0] }, Range(4, 5)));
        }

        [Fact]
        public void IntersectionCount_Gaps()
        {
            var ranges = new[] { Range(0, 5), Range(7, 10) };
            var intersectionCounts = ranges.IntersectionCount().ToList();
            intersectionCounts[0].Should().Be(new NumberRangeIntersectionCount<int>(new[] { ranges[0] }, Range(0, 5)));
            intersectionCounts[1].Should().Be(new NumberRangeIntersectionCount<int>(new INumberRange<int>[0], Range(5, 7)));
            intersectionCounts[2].Should().Be(new NumberRangeIntersectionCount<int>(new[] { ranges[1] }, Range(7, 10)));
        }

        [Fact]
        public void IntersectionCount_OuterNonStrictUpperBounds()
        {
            var ranges = new[] { Range(0, 5, false, false), Range(1, 4) };
            var intersectionCounts = ranges.IntersectionCount().ToList();
            intersectionCounts[0].Should().Be(new NumberRangeIntersectionCount<int>(new[] { ranges[0] }, Range(0, 1)));
            intersectionCounts[1].Should().Be(new NumberRangeIntersectionCount<int>(new[] { ranges[0], ranges[1] }, Range(1, 4)));
            intersectionCounts[2].Should().Be(new NumberRangeIntersectionCount<int>(new[] { ranges[0] }, Range(4, 5, false, false)));
        }

        [Fact]
        public void IntersectionCount_InnerNonStrictUpperBounds()
        {
            var ranges = new[] { Range(0, 5), Range(1, 4, false, false) };
            var intersectionCounts = ranges.IntersectionCount().ToList();
            intersectionCounts[0].Should().Be(new NumberRangeIntersectionCount<int>(new[] { ranges[0] }, Range(0, 1)));
            intersectionCounts[1].Should().Be(new NumberRangeIntersectionCount<int>(new[] { ranges[0], ranges[1] }, Range(1, 4, false, false)));
            intersectionCounts[2].Should().Be(new NumberRangeIntersectionCount<int>(new[] { ranges[0] }, Range(4, 5, true)));
        }

        [Fact]
        public void IntersectionCount_OuterStrictLowerBounds()
        {
            var ranges = new[] { Range(0, 5, true), Range(1, 4) };
            var intersectionCounts = ranges.IntersectionCount().ToList();
            intersectionCounts[0].Should().Be(new NumberRangeIntersectionCount<int>(new[] { ranges[0] }, Range(0, 1, true)));
            intersectionCounts[1].Should().Be(new NumberRangeIntersectionCount<int>(new[] { ranges[0], ranges[1] }, Range(1, 4)));
            intersectionCounts[2].Should().Be(new NumberRangeIntersectionCount<int>(new[] { ranges[0] }, Range(4, 5)));
        }

        [Fact]
        public void IntersectionCount_InnerStrictLowerBounds()
        {
            var ranges = new[] { Range(0, 5), Range(1, 4, true) };
            var intersectionCounts = ranges.IntersectionCount().ToList();
            intersectionCounts[0].Should().Be(new NumberRangeIntersectionCount<int>(new [] { ranges[0] }, Range(0, 1, false, false)));
            intersectionCounts[1].Should().Be(new NumberRangeIntersectionCount<int>(new [] { ranges[0], ranges[1] }, Range(1, 4, true)));
            intersectionCounts[2].Should().Be(new NumberRangeIntersectionCount<int>(new [] { ranges[0] }, Range(4, 5)));
        }

        [Fact]
        public void Size()
        {
            var range1 = Range(0, 5, false, true);
            range1.Size.Should().Be(5, range1.ToString());
            var range2 = Range(0, 5, true, true);
            range2.Size.Should().Be(4, range2.ToString());
            var range3 = Range(0, 5, true, false);
            range3.Size.Should().Be(5, range3.ToString());
            var range4 = Range(0, 5, false, false);
            range4.Size.Should().Be(6, range4.ToString());
        }
    }
}
