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); var queryWitsString = db.Set() .Where(d => d.IdTelemetry == telemetry.Id); var queryWitsFloat = db.Set() .Where(d => d.IdTelemetry == telemetry.Id); var recordAllInt = await GetItemsOrDefaultAsync(queryWitsInt, dateBeginUtc, dateEnd, filterByDateEnd, approxPointsCount, timezone.Hours, token); var recordAllFloat = await GetItemsOrDefaultAsync(queryWitsFloat, dateBeginUtc, dateEnd, filterByDateEnd, approxPointsCount,timezone.Hours, token); var recordAllString = await GetItemsOrDefaultAsync(queryWitsString, dateBeginUtc, 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 }).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, timezoneHours); db.WitsItemString.Add(entity.Adapt()); } if (jsonValue.value is float valueFloat) { var entity = ConvertToEntity(dto, valueFloat, timezoneHours); db.WitsItemFloat.Add(entity.Adapt()); } if (jsonValue.value is int valueInt) { var entity = ConvertToEntity(dto, valueInt, timezoneHours); db.WitsItemInt.Add(entity.Adapt()); } } await db.SaveChangesAsync(token); } private static async Task> GetItemsOrDefaultAsync(IQueryable> query, DateTimeOffset dateBeginUtc, DateTimeOffset dateEnd, bool filterByDateEnd, int approxPointsCount, double timezoneHours , CancellationToken token) where T: notnull { //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 .Where(d => d.DateTime >= dateBeginUtc) .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, double timezoneHours) where Tvalue: notnull { var entity = record.Adapt>(); entity.DateTime = record.Date.ToUtcDateTimeOffset(timezoneHours); entity.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; } = default!; } } #nullable disable }