using AsbCloudApp.Data; using AsbCloudApp.Data.Subsystems; using AsbCloudApp.Requests; using AsbCloudApp.Services; using AsbCloudApp.Services.Subsystems; using AsbCloudDb; using AsbCloudDb.Model; using AsbCloudDb.Model.Subsystems; using Mapster; using Microsoft.EntityFrameworkCore; using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; namespace AsbCloudInfrastructure.Services.Subsystems { #nullable enable internal class SubsystemOperationTimeService : ISubsystemOperationTimeService { private readonly IAsbCloudDbContext db; private readonly IWellService wellService; private readonly ICrudService subsystemService; public SubsystemOperationTimeService(IAsbCloudDbContext db, IWellService wellService, ICrudService subsystemService) { this.db = db; this.wellService = wellService; this.subsystemService = subsystemService; } public async Task DeleteAsync(SubsystemOperationTimeRequest request, CancellationToken token) { var well = await wellService.GetOrDefaultAsync(request.IdWell, token); if (well?.IdTelemetry is null || well.Timezone is null) return 0; var query = BuildQuery(request); if (query is null) return 0; db.SubsystemOperationTimes.RemoveRange(query); return await db.SaveChangesAsync(token); } public async Task?> GetOperationTimeAsync(SubsystemOperationTimeRequest request, CancellationToken token) { var well = await wellService.GetOrDefaultAsync(request.IdWell, token); if (well?.IdTelemetry is null || well.Timezone is null) return null; var query = BuildQuery(request); if (query is null) return null; if (request.SelectMode == SubsystemOperationTimeRequest.SelectModeInner) { if (request.GtDate is not null) query = query.Where(o => o.DateStart >= request.GtDate.Value || o.DateEnd >= request.GtDate.Value); if (request.LtDate is not null) query = query.Where(o => o.DateEnd <= request.LtDate.Value || o.DateStart <= request.LtDate.Value); } if (request.SelectMode == SubsystemOperationTimeRequest.SelectModeTrim) { if (!request.GtDate.HasValue) throw new ArgumentNullException(nameof(request.GtDate)); var begin = request.GtDate.Value.ToUtcDateTimeOffset(well.Timezone.Hours); if (!request.LtDate.HasValue) throw new ArgumentNullException(nameof(request.LtDate)); var end = request.LtDate.Value.ToUtcDateTimeOffset(well.Timezone.Hours); var data = query.ToList(); data = Trim(data, begin, end); return data.Select(o => Convert(o, well)); } var dtos = query.Select(o => Convert(o, well)); return dtos; } public async Task?> GetStatAsync(SubsystemOperationTimeRequest request, CancellationToken token) { request.SelectMode = SubsystemOperationTimeRequest.SelectModeTrim; var data = await GetOperationTimeAsync(request, token); if (data is null) return null; var statList = CalcStat(data, request); return statList; } private List Trim(List data, DateTimeOffset gtDate, DateTimeOffset ltDate) { var ItemsNormal = data.Where(q => (q.DateStart >= gtDate) && (q.DateEnd <= ltDate)).ToList(); var itemsToTrim = data.Where(q => (q.DateStart < gtDate && q.DateEnd <= ltDate && q.DateEnd > gtDate) || (q.DateStart >= gtDate && q.DateEnd > ltDate && q.DateStart < ltDate) || (q.DateStart < gtDate && q.DateEnd > ltDate)) .Select(o => new SubsystemOperationTime { Id = o.Id, DateStart = (o.DateStart >= gtDate) && (o.DateStart <= ltDate) ? o.DateStart : gtDate, DateEnd = (o.DateEnd >= gtDate) && (o.DateEnd <= ltDate) ? o.DateEnd : ltDate, IdSubsystem = o.IdSubsystem, IdTelemetry = o.IdTelemetry, DepthEnd = (o.DateEnd >= gtDate) && (o.DateEnd <= ltDate) ? o.DepthEnd : null , DepthStart = (o.DateStart >= gtDate) && (o.DateStart <= ltDate) ? o.DepthStart : null, Subsystem = o.Subsystem, Telemetry = o.Telemetry }) .ToList(); ItemsNormal.AddRange(itemsToTrim); return ItemsNormal.OrderBy(o => o.DateStart).ToList(); } private IEnumerable CalcStat(IEnumerable listOperationTimeSubsystems, SubsystemOperationTimeRequest request) { var result = new List(); var groupedDataSubsystems = listOperationTimeSubsystems .GroupBy(x => x.IdSubsystem); var periodGroupTotal = groupedDataSubsystems .Sum(g => g.Sum(o=> (o.DateEnd - o.DateStart).TotalHours)); var gtDate = request.GtDate ?? listOperationTimeSubsystems.Min(d => d.DateStart); var ltDate = request.LtDate ?? listOperationTimeSubsystems.Max(d => d.DateEnd); var periodRequest = listOperationTimeSubsystems .Sum(o => (o.DateEnd - o.DateStart).TotalHours); foreach (var item in groupedDataSubsystems) { var periodGroup = item.Sum(g => (g.DateEnd - g.DateStart).TotalHours); int idSubsystem = item.First().IdSubsystem; var subsystemStat = new SubsystemStatDto() { IdSubsystem = idSubsystem, SubsystemName = subsystemService.GetOrDefault(idSubsystem)?.Name ?? "unknown", UsedTimeHours =periodGroup, KUsage = 1d*periodGroup / periodRequest, K2 = 1d*periodGroup / periodGroupTotal, }; result.Add(subsystemStat); } return result; } private IQueryable? BuildQuery(SubsystemOperationTimeRequest request) { var well = wellService.GetOrDefault(request.IdWell); if (well?.IdTelemetry is null || well.Timezone is null) return null; var query = db.SubsystemOperationTimes .Include(o => o.Subsystem) .Where(o => o.IdTelemetry == well.IdTelemetry); if(request.IdsSubsystems?.Any() == true) query = query.Where(o => request.IdsSubsystems.Contains(o.IdSubsystem)); if (request.GtDate is not null && request.LtDate is not null) { query = query.Where(o => (o.DateStart >= request.GtDate.Value.ToUtcDateTimeOffset(well.Timezone.Hours)) ||(o.DateEnd <= request.LtDate.Value.ToUtcDateTimeOffset(well.Timezone.Hours))); } else if (request.GtDate is not null) query = query.Where(o => o.DateStart >= request.GtDate.Value.ToUtcDateTimeOffset(well.Timezone.Hours)); else if (request.LtDate is not null) query = query.Where(o => o.DateEnd <= request.LtDate.Value.ToUtcDateTimeOffset(well.Timezone.Hours)); if (request.GtDepth is not null) query = query.Where(o => o.DepthStart >= request.GtDepth.Value); if (request.LtDepth is not null) query = query.Where(o => o.DepthEnd <= request.LtDepth.Value); if (request?.SortFields?.Any() == true) { query = query.SortBy(request.SortFields); } else query = query .OrderBy(o => o.DateStart) .ThenBy(o => o.DepthStart); if (request?.Skip > 0) query = query.Skip((int)request.Skip); if (request?.Take > 0) query = query.Take((int)request.Take); else query = query.Take(3000); return query; } private SubsystemOperationTimeDto Convert(SubsystemOperationTime operationTime, WellDto well) { var dto = operationTime.Adapt(); dto.DateStart = operationTime.DateStart.ToRemoteDateTime(well.Timezone.Hours); dto.DateEnd = operationTime.DateEnd.ToRemoteDateTime(well.Timezone.Hours); return dto; } } #nullable disable }