using AsbCloudApp.Data;
using AsbCloudApp.Repositories;
using AsbCloudInfrastructure.Services;
using AsbCloudInfrastructure.Services.Trajectory;
using Moq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Xunit;

namespace AsbCloudWebApi.Tests.ServicesTests
{
    public class TrajectoryVisualizationServiceTest
    {
        private Mock<IPlannedTrajectoryRepository> MakePlannedTrajectoryRepositoryMock(IEnumerable<PlannedTrajectoryDto> dateForGetMethod)
        {
            var mock = new Mock<IPlannedTrajectoryRepository>();

            mock.Setup(r => r.GetAsync(It.IsAny<int>(), It.IsAny<CancellationToken>()))
                .Returns(Task.FromResult(dateForGetMethod));

            return mock;
        }

        [Fact]
        public async Task GetTrajectoryAsync_SameCounts()
        {
            var plannedTrajectory = new PlannedTrajectoryDto[]
            {
                new() { AzimuthGeo = 0d, ZenithAngle = 0d, WellboreDepth = 0d},
                new() { AzimuthGeo = 0d, ZenithAngle = 0d, WellboreDepth = 10d},
                new() { AzimuthGeo = 0d, ZenithAngle = 30d, WellboreDepth = 20d},
                new() { AzimuthGeo = 30d, ZenithAngle = 0d, WellboreDepth = 30d},
                new() { AzimuthGeo = 30d, ZenithAngle = 90d, WellboreDepth = 40d},
                new() { AzimuthGeo = 0d, ZenithAngle = 0d, WellboreDepth = 50d},
            };

            var mock = MakePlannedTrajectoryRepositoryMock(plannedTrajectory);
            var service = new TrajectoryVisualizationService(mock.Object);
            var result = await service.GetTrajectoryAsync(1, CancellationToken.None);

            Assert.Equal(plannedTrajectory.Length, result.Count());
        }

        [Fact]
        public async Task GetTrajectoryAsync_StraigthBore()
        {
            var plannedTrajectory = new PlannedTrajectoryDto[]
            {
                new() { AzimuthGeo = 0d, ZenithAngle = 0d, WellboreDepth = 0d},
                new() { AzimuthGeo = 0d, ZenithAngle = 0d, WellboreDepth = 0d},
                new() { AzimuthGeo = 0d, ZenithAngle = 0d, WellboreDepth = 20d},
                new() { AzimuthGeo = 0d, ZenithAngle = 0d, WellboreDepth = 20d},
                new() { AzimuthGeo = 0d, ZenithAngle = 0d, WellboreDepth = 30d},
                new() { AzimuthGeo = 0d, ZenithAngle = 0d, WellboreDepth = 50d},
            };

            var mock = MakePlannedTrajectoryRepositoryMock(plannedTrajectory);
            var service = new TrajectoryVisualizationService(mock.Object);
            var result = await service.GetTrajectoryAsync(1, CancellationToken.None);
            var lastPoint = result.Last();

            Assert.Equal(0d, lastPoint.X, 0.1d);
            Assert.Equal(0d, lastPoint.Y, 0.1d);
            Assert.Equal(50d, lastPoint.Z, 0.1d);
        }

        [Fact]
        public async Task GetTrajectoryAsync_Match()
        {
            var plannedTrajectory = new PlannedTrajectoryDto[]
            {
                new() { AzimuthGeo = 0d, ZenithAngle = 0d, WellboreDepth = 0d},
                new() { AzimuthGeo = 30d, ZenithAngle = 30d, WellboreDepth = 10d},
                new() { AzimuthGeo = 0d, ZenithAngle = 0d, WellboreDepth = 20d},
            };

            var mock = MakePlannedTrajectoryRepositoryMock(plannedTrajectory);
            var service = new TrajectoryVisualizationService(mock.Object);
            var result = await service.GetTrajectoryAsync(1, CancellationToken.None);
            var lastPoint = result.Last();
            var tolerance = 0.001d;

            Assert.InRange(lastPoint.Z, 10 + tolerance, 20 - tolerance);
            Assert.InRange(lastPoint.Y, 0 + tolerance, 10 - tolerance);
            Assert.InRange(lastPoint.X, 0 + tolerance, 10 - tolerance);
        }
    }
}