using AsbCloudApp.Data;
using AsbCloudApp.Requests;
using AsbCloudApp.Services;
using AsbCloudDb.Model;
using AsbCloudInfrastructure.Repository;
using AsbCloudInfrastructure.Services;
using AsbCloudInfrastructure.Services.Cache;
using AsbCloudInfrastructure.Services.DetectOperations;
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 DetectedOperationServiceTest
    {
        private readonly AsbCloudDbContext context;
        private readonly CacheDb cacheDb;
        private readonly DetectedOperationService service;
        private readonly DetectedOperationRequest request;
        private Deposit deposit = new Deposit { Id = 1, Caption = "Депозит 1" };
        private Cluster cluster = new Cluster { Id = 1, Caption = "Кластер 1", IdDeposit = 1, Timezone = new SimpleTimezone() };
        private WellDto wellDto = new WellDto
        {
            Id = 1,
            Caption = "Test well 1",
            IdTelemetry = 1,
            IdCluster = 1,
            Timezone = new SimpleTimezoneDto { Hours = 5 }
        };
        private Well well = new Well
        {
            Id = 1,
            Caption = "Test well 1",
            IdTelemetry = 1,
            IdCluster = 1,
            Timezone = new SimpleTimezone { Hours = 5 }
        };
        private Driller driller = new Driller
        {
            Id = 1,
            Name = "Тестовый",
            Patronymic = "Тест",
            Surname = "Тестович"
        };
        private List<DetectedOperation> do1 = new List<DetectedOperation> {
        new DetectedOperation
        {
            Id = 1,
            IdCategory = 1,
            IdTelemetry = 1,
            DateStart = DateTimeOffset.Parse("2022-05-16T10:00:00.286Z"),
            DateEnd = DateTimeOffset.Parse("2022-05-16T18:00:00.286Z"),
            DepthStart = 100,
            Value = 50,
            DepthEnd = 1000
        },
        new DetectedOperation
        {
            Id = 2,
            IdCategory = 1,
            IdTelemetry = 1,
            DateStart = DateTimeOffset.Parse("2022-05-16T10:00:00.286Z"),
            DateEnd = DateTimeOffset.Parse("2022-05-16T18:00:00.286Z"),
            DepthStart = 100,
            Value = 10,
            DepthEnd = 1000
        }};
        private Telemetry telemetry = new Telemetry
        {
            Id = 1,
            RemoteUid = Guid.NewGuid().ToString()
        };
        private OperationValue ovd = new OperationValue
        {
            Id = 1,
            StandardValue = 200,
            TargetValue = 100,
            DepthEnd = 300,
            DepthStart = 100,
            IdOperationCategory=1,
            IdWell = 1
        };
        private List<Schedule> sch = new List<Schedule> { new Schedule
        {
            Id = 1,
            IdDriller = 1,
            IdWell = 1,
            DrillStart = DateTimeOffset.Parse("2022-05-16T10:00:00.286Z"),
            DrillEnd = DateTimeOffset.Parse("2022-05-16T18:00:00.286Z"),
            ShiftStart = new TimeOnly(10, 00),
            ShiftEnd = new TimeOnly(18, 00)
        }, new Schedule
        {
            Id = 2,
            IdDriller = 1,
            IdWell = 1,
            DrillStart = DateTimeOffset.Parse("2022-05-17T10:00:00.286Z"),
            DrillEnd = DateTimeOffset.Parse("2022-05-17T18:00:00.286Z"),
            ShiftStart = new TimeOnly(10, 00),
            ShiftEnd = new TimeOnly(18, 00)
        } };

        public DetectedOperationServiceTest()
        {
            context = TestHelpter.MakeTestContext();
            context.SaveChanges();

            context.Telemetries.Add(telemetry);
            context.Deposits.Add(deposit);
            context.Clusters.Add(cluster);
            context.Wells.Add(well);
            context.Drillers.Add(driller);
            context.DetectedOperations.AddRange(do1);
            context.OperationValues.Add(ovd);
            context.Schedule.AddRange(sch);

            context.SaveChanges();

            var timezone = new SimpleTimezoneDto { Hours = 5 };
            var wellServiceMock = new Mock<IWellService>();
            wellServiceMock.Setup(s => s.GetTimezone(It.IsAny<int>())).Returns(timezone);
            wellServiceMock.Setup(s => s.GetOrDefaultAsync(It.IsAny<int>(),CancellationToken.None)).Returns(Task.Run(() => wellDto));
            //var operationValueService = new OperationValueService(context);
            var scheduleService = new ScheduleRepository(context, wellServiceMock.Object);

            service = new DetectedOperationService(context, wellServiceMock.Object, /*operationValueService*/ null, scheduleService);
            request = new DetectedOperationRequest
            {
                IdWell = 1,
                IdsCategories = new int[] { 1 },
            };
            AsbCloudInfrastructure.DependencyInjection.MapsterSetup();
        }

        ~DetectedOperationServiceTest()
        {

        }

        [Fact]
        public async Task Count_grouping_by_driller()
        {
            var list = await service.GetAsync(request, CancellationToken.None);
            Assert.Equal(2, list.Stats.First().Count);
        }

        [Fact]
        public async Task AvgVal_grouping_by_driller()
        {
            var list = await service.GetAsync(request, CancellationToken.None);
            Assert.Equal(30, list.Stats.First().AverageValue);
        }

        [Fact]
        public async Task AvgTargetVal_grouping_by_driller()
        {
            var list = await service.GetAsync(request, CancellationToken.None);
            Assert.Equal(100, list.Stats.First().AverageTargetValue);
        }
        [Fact]
        public async Task Loss_grouping_by_driller()
        {
            var list = await service.GetAsync(request, CancellationToken.None);
            Assert.Equal(0, list.Stats.First().Loss);
        }
        [Fact]
        public async Task Efficiency_grouping_by_driller()
        {
            var list = await service.GetAsync(request, CancellationToken.None);
            Assert.Equal(100, list.Stats.First().Efficiency);
        }
        [Fact]
        public async Task GroupCount_grouping_by_driller()
        {
            var list = await service.GetAsync(request, CancellationToken.None);
            Assert.Equal(1, list.Stats.Count());
        }

    }
}