using AsbCloudDb.Model;
using AsbCloudInfrastructure.Services.SAUB;
using Moq;
using System;
using System.Linq;
using System.Threading.Tasks;
using Xunit;

namespace AsbCloudWebApi.Tests.CacheTests
{
    public class TelemetryDataCacheTest
    {
        private const int IdTelemetryOk = 10;
        private static readonly DateTime baseDate = DateTime.Now;
        private static readonly SimpleTimezone timezone = new() { Hours = TimeZoneInfo.Local.BaseUtcOffset.TotalHours };

        private static readonly Well[] wellData = new Well[]{
            new(){ Id = 1, IdTelemetry = IdTelemetryOk, IdState = 1, Caption = "",  Timezone = timezone}
        };
        private static readonly TTelemetryData[] telemetryData = new TTelemetryData[]{
            new ( IdTelemetryOk, baseDate.AddSeconds(1), timezone.Hours ),
            new ( IdTelemetryOk, baseDate.AddSeconds(2), timezone.Hours ),
            new ( IdTelemetryOk, baseDate.AddSeconds(3), timezone.Hours ),
            new ( IdTelemetryOk, baseDate.AddSeconds(4), timezone.Hours ),
        };
        private readonly Mock<IAsbCloudDbContext> dbMock;
        
        private TelemetryDataCache<TTelemetryData> cacheTest;

        public class TTelemetryData : ITelemetryData, AsbCloudApp.Data.ITelemetryData
        {
            private DateTimeOffset _dateTime;

            public TTelemetryData(int idTelemetry, DateTime dateTime, double hoursOffset)
            {
                IdTelemetry = idTelemetry;
                DateTime = dateTime;
                var offset = TimeSpan.FromHours(hoursOffset);
                var dateTimeUTC = DateTime.SpecifyKind(dateTime, DateTimeKind.Unspecified);
                _dateTime = new DateTimeOffset(dateTimeUTC, offset)
                    .ToUniversalTime();
            }

            public int IdTelemetry { get; set; }
            public DateTime DateTime { get; set; }
            DateTimeOffset ITelemetryData.DateTime { get => _dateTime; set => _dateTime = value; }
        }

        public TelemetryDataCacheTest()
        {
            dbMock = new Mock<IAsbCloudDbContext>();
            dbMock
                .AddDbSetMock(wellData)
                .AddDbSetMock(telemetryData);

            cacheTest = TelemetryDataCache<TTelemetryData>.GetInstance<TTelemetryData>(dbMock.Object, out Task cacheInitialization);
            cacheInitialization.Wait();
        }

        [Fact]
        public void Get_existing_cache_returns_some()
        {
            var startDate = baseDate.AddSeconds(3);
            var data = cacheTest.GetOrDefault(IdTelemetryOk, startDate, 600, 600);
            Assert.NotNull(data);
            Assert.NotEmpty(data);
        }

        [Fact]
        public void Get_non_existing_cache_returns_null()
        {
            var startDate = baseDate.AddSeconds(-1);
            var data = cacheTest.GetOrDefault(IdTelemetryOk, startDate, 600, 600);
            Assert.Null(data);
        }

        [Fact]
        public void Add_new_data_should_replace_IdTelemetry()
        {
            var startDate = baseDate.AddSeconds(4);
            var newTelemetryData = new TTelemetryData[]{
                new ( 0, startDate, timezone.Hours),
                new ( 0, startDate.AddSeconds(1), timezone.Hours),
            };
            cacheTest.AddRange(IdTelemetryOk, newTelemetryData);
            var data = cacheTest.GetOrDefault(IdTelemetryOk, startDate, 600, 600);

            Assert.NotNull(data);
            Assert.True(data?.Count() > 2);
            Assert.All(data!, p => Assert.Equal(IdTelemetryOk, p.IdTelemetry));
        }
    }
}