using AsbCloudApp.Data.GTR; using AsbCloudApp.Repositories; using AsbCloudApp.Services; using AsbCloudDb.Model; using AsbCloudDb.Model.GTR; using Mapster; using Microsoft.EntityFrameworkCore; using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; namespace AsbCloudInfrastructure.Repository { #nullable enable public class GtrWitsRepository : IGtrRepository { private readonly IAsbCloudDbContext db; private readonly ITelemetryService telemetryService; public GtrWitsRepository( IAsbCloudDbContext db, ITelemetryService telemetryService) { this.db = db; this.telemetryService = telemetryService; } public async Task> GetAsync(int idWell, DateTime dateBegin = default, double intervalSec = 600, int approxPointsCount = 1024, CancellationToken token = default) { var telemetry = telemetryService.GetOrDefaultTelemetryByIdWell(idWell); if (telemetry is null) return Enumerable.Empty(); var timezone = telemetryService.GetTimezone(telemetry.Id); var filterByDateEnd = dateBegin != default; DateTimeOffset dateBeginUtc; if (dateBegin == default) { dateBeginUtc = telemetryService.GetLastTelemetryDate(telemetry.Id) .ToUtcDateTimeOffset(timezone.Hours); if (dateBeginUtc != default) dateBeginUtc = dateBeginUtc.AddSeconds(-intervalSec); } else { dateBeginUtc = dateBegin.ToUtcDateTimeOffset(timezone.Hours); } if (dateBeginUtc == default) dateBeginUtc = DateTime.UtcNow.AddSeconds(-intervalSec); var dateEnd = dateBeginUtc.AddSeconds(intervalSec); var queryWitsInt = db.Set() .Where(d => d.IdTelemetry == telemetry.Id && d.DateTime >= dateBeginUtc); var queryWitsString = db.Set() .Where(d => d.IdTelemetry == telemetry.Id && d.DateTime >= dateBeginUtc); var queryWitsFloat = db.Set() .Where(d => d.IdTelemetry == telemetry.Id && d.DateTime >= dateBeginUtc); var recordAllInt = await GetItemsOrDefaultAsync(queryWitsInt, dateEnd, filterByDateEnd, approxPointsCount, timezone.Hours, token); var recordAllFloat = await GetItemsOrDefaultAsync(queryWitsFloat, dateEnd, filterByDateEnd, approxPointsCount,timezone.Hours, token); var recordAllString = await GetItemsOrDefaultAsync(queryWitsString, dateEnd, filterByDateEnd, approxPointsCount, timezone.Hours, token); var groupRecordDate = (recordAllFloat.Union(recordAllInt)).Union(recordAllString) .GroupBy(g => new { g.IdRecord, g.Date }).ToList(); var dtos = groupRecordDate.Select(g => new WitsRecordDto { Id = g.Key.IdRecord, Date = g.Key.Date, IdTelemetry = g.First().IdTelemetry, Items = g.Select(r => new { Key = r.IdItem, Value = r.Item }).ToList().ToDictionary(x => x.Key, x => x.Value) }); return dtos; } public async Task SaveDataAsync(int idTelemetry, WitsRecordDto dto, CancellationToken token) { if (dto is null) return; var timezoneHours = telemetryService.GetTimezone(idTelemetry).Hours; foreach (var item in dto.Items) { var jsonValue = item.Value; if(jsonValue.Value is string valueString) { var entity = ConvertToEntity(dto, valueString, item.Key, timezoneHours); db.WitsItemString.Add(entity.Adapt()); } if (jsonValue.Value is float valueFloat) { var entity = ConvertToEntity(dto, valueFloat, item.Key, timezoneHours); db.WitsItemFloat.Add(entity.Adapt()); } if (jsonValue.Value is int valueInt) { var entity = ConvertToEntity(dto, valueInt, item.Key, timezoneHours); db.WitsItemInt.Add(entity.Adapt()); } } await db.SaveChangesAsync(token); } private static async Task> GetItemsOrDefaultAsync(IQueryable> query, DateTimeOffset dateEnd, bool filterByDateEnd, int approxPointsCount, double timezoneHours , CancellationToken token) { if (filterByDateEnd) query = query.Where(d => d.DateTime <= dateEnd); var fullDataCount = await query.CountAsync(token) .ConfigureAwait(false); if (fullDataCount == 0) return Enumerable.Empty(); if (fullDataCount > 1.75 * approxPointsCount) { var m = (int)Math.Round(1d * fullDataCount / approxPointsCount); if (m > 1) query = query.Where((d) => (((d.DateTime.DayOfYear * 24 + d.DateTime.Hour) * 60 + d.DateTime.Minute) * 60 + d.DateTime.Second) % m == 0); } var entities = await query .OrderBy(d => d.DateTime) .AsNoTracking() .ToListAsync(token) .ConfigureAwait(false); var items = entities.Select(e => new ItemRecord { IdRecord = e.IdRecord, IdTelemetry = e.IdTelemetry, Date = e.DateTime.ToRemoteDateTime(timezoneHours), IdItem = e.IdItem, Item = new JsonValue(e.Value) }); return items; } private static WitsItemBase ConvertToEntity(WitsRecordDto record, Tvalue value, int idItems, double timezoneHours) { var entity = new WitsItemBase { IdTelemetry = record.IdTelemetry, DateTime = record.Date.ToUtcDateTimeOffset(timezoneHours), IdRecord = record.Id, IdItem = idItems, Value = value, }; return entity; } internal class ItemRecord { public int IdRecord { get; set; } public int IdTelemetry { get; set; } public DateTime Date { get; set; } public int IdItem { get; set; } public JsonValue Item { get; set; } } } #nullable disable }