using AsbCloudApp.Data;
using AsbCloudApp.Repositories;
using AsbCloudApp.Services;
using AsbCloudDb.Model;
using Mapster;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace AsbCloudInfrastructure.Repository
{
    public class DataSaubStatRepository : IDataSaubStatRepository
    {
        private readonly IAsbCloudDbContext db;
        private readonly ITelemetryService telemetryService;

        public DataSaubStatRepository(IAsbCloudDbContext dbContext, ITelemetryService telemetryService)
        {
            db = dbContext;
            this.telemetryService = telemetryService;

        }

        public async Task<IEnumerable<DataSaubStatDto>> GetLastsAsync(int[] idTelemetries, CancellationToken token)
        {
            var timeZoneOffsets = idTelemetries
                .Distinct()
                .ToDictionary(idTelemetry => idTelemetry, idTelemetry => TimeSpan.FromHours(telemetryService.GetTimezone(idTelemetry).Hours));

            var stats = await db.Set<DataSaubStat>()
                .Where(s => idTelemetries.Contains(s.IdTelemetry))
                .GroupBy(s => s.IdTelemetry, (key, group) => group.OrderByDescending(el => el.DateEnd).First())
                .ToArrayAsync(token);

            var result = stats.Select(s => ConvertToDto(s, timeZoneOffsets[s.IdTelemetry]));

            return result;
        }

        public async Task<IEnumerable<DataSaubStatDto>> GetAsync(int idTelemetry, DateTimeOffset geDate, DateTimeOffset leDate, CancellationToken token)
        {
            var timeSpan = TimeSpan.FromHours(telemetryService.GetTimezone(idTelemetry).Hours);
            var geDateUtc = geDate.ToUniversalTime();
            var leDateUtc = leDate.ToUniversalTime();

            var stats = await db.Set<DataSaubStat>()
                .Where(s => s.IdTelemetry == idTelemetry)
                .Where(s => s.DateStart >= geDateUtc)
                .Where(s => s.DateEnd <= leDateUtc)
                .ToArrayAsync(token);

            var result = stats.Select(s => ConvertToDto(s, timeSpan));

            return result;
        }

        public async Task<int> InsertRangeAsync(IEnumerable<DataSaubStatDto> dataSaubStats, CancellationToken token)
        {
            var entities = dataSaubStats.Select(data => ConvertToEntity(data));
            db.Set<DataSaubStat>().AddRange(entities);
            return await db.SaveChangesAsync(token);
        }

        private static DataSaubStatDto ConvertToDto(DataSaubStat entity, TimeSpan timeSpan)
        {
            var dto = entity.Adapt<DataSaubStatDto>();
            dto.DateStart = dto.DateStart.ToOffset(timeSpan);
            dto.DateEnd = dto.DateEnd.ToOffset(timeSpan);

            return dto;
        }

        private static DataSaubStat ConvertToEntity(DataSaubStatDto dto)
        {
            var entity = dto.Adapt<DataSaubStat>();
            entity.DateStart = dto.DateStart.ToUniversalTime();
            entity.DateEnd = dto.DateEnd.ToUniversalTime();

            return entity;
        }
    }
}