using AsbCloudApp.Data; using AsbCloudApp.Requests; using AsbCloudApp.Services; using AsbCloudDb.Model; using Microsoft.EntityFrameworkCore; using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; namespace AsbCloudInfrastructure.Services; public class SlipsStatService : ISlipsStatService { private readonly IAsbCloudDbContext db; public SlipsStatService(IAsbCloudDbContext db) { this.db = db; } public async Task> GetAllAsync(OperationStatRequest request, CancellationToken token) { if (request.DateStartUTC.HasValue) request.DateStartUTC = DateTime.SpecifyKind(request.DateStartUTC.Value, DateTimeKind.Utc); if (request.DateEndUTC.HasValue) request.DateEndUTC = DateTime.SpecifyKind(request.DateEndUTC.Value, DateTimeKind.Utc); var schedulesQuery = db.Schedule .Include(s => s.Well) .Include(s => s.Driller) .AsNoTracking(); if (request.DateStartUTC.HasValue && request.DateEndUTC.HasValue) schedulesQuery = schedulesQuery. Where(s => s.DrillStart >= request.DateStartUTC && s.DrillEnd <= request.DateEndUTC); var schedules = await schedulesQuery.ToArrayAsync(token); var wells = schedules .Select(d => d.Well) .Where(well => well.IdTelemetry != null) .GroupBy(w => w.Id) .ToDictionary(g => g.Key, g => g.First().IdTelemetry!.Value); var idsWells = wells.Keys; var idsTelemetries = wells.Values; var telemetries = wells.ToDictionary(wt => wt.Value, wt => wt.Key); var factWellOperationsQuery = db.WellOperations .Where(o => idsWells.Contains(o.IdWell)) .Where(o => o.IdType == 1) .Include(o => o.WellSectionType) .AsNoTracking(); if (request.DateStartUTC.HasValue && request.DateEndUTC.HasValue) factWellOperationsQuery = factWellOperationsQuery .Where(o => o.DateStart.AddHours(o.DurationHours) > request.DateStartUTC && o.DateStart < request.DateEndUTC); var factWellOperations = await factWellOperationsQuery.ToArrayAsync(token); var sections = factWellOperations .GroupBy(o => new { o.IdWell, o.IdWellSectionType }) .Select(g => new { g.Key.IdWell, g.Key.IdWellSectionType, DepthStart = g.Min(o => o.DepthStart), DepthEnd = g.Max(o => o.DepthEnd), g.First().WellSectionType.Caption }); var detectedOperationsQuery = db.DetectedOperations .Where(o => idsTelemetries.Contains(o.IdTelemetry)) .Where(o => o.IdCategory == WellOperationCategory.IdSlipsTime) .AsNoTracking(); if (request.DateStartUTC.HasValue) detectedOperationsQuery = detectedOperationsQuery .Where(o => o.DateEnd > request.DateStartUTC); if (request.DateEndUTC.HasValue) detectedOperationsQuery = detectedOperationsQuery .Where(o => o.DateStart < request.DateEndUTC); if (request.DurationMinutesMin.HasValue) { var durationMinutesMin = TimeSpan.FromMinutes(request.DurationMinutesMin.Value); detectedOperationsQuery = detectedOperationsQuery .Where(o => o.DateEnd - o.DateStart >= durationMinutesMin); } if (request.DurationMinutesMax.HasValue) { var durationMinutesMax = TimeSpan.FromMinutes(request.DurationMinutesMax.Value); detectedOperationsQuery = detectedOperationsQuery .Where(o => o.DateEnd - o.DateStart <= durationMinutesMax); } var detectedOperations = await detectedOperationsQuery .ToArrayAsync(token); var detectedOperationsGroupedByDrillerAndSection = detectedOperations.Select(o => new { Operation = o, IdWell = telemetries[o.IdTelemetry], schedules.FirstOrDefault(s => s.IdWell == telemetries[o.IdTelemetry] && s.DrillStart <= o.DateStart && s.DrillEnd > o.DateStart && ( s.ShiftStart > s.ShiftEnd ) ^ (s.ShiftStart <= new TimeDto(o.DateStart.DateTime).MakeTimeOnly() && s.ShiftEnd > new TimeDto(o.DateStart.DateTime).MakeTimeOnly() )) ?.Driller, Section = sections.FirstOrDefault(s => s.IdWell == telemetries[o.IdTelemetry] && s.DepthStart <= o.DepthStart && s.DepthEnd >= o.DepthStart) }) .Where(o => o.Driller != null) .Where(o => o.Section != null) .Select(o => new { o.Operation, o.IdWell, Driller = o.Driller!, Section = o.Section! }) .GroupBy(o => new { o.Driller.Id, o.Section.IdWellSectionType }); var factWellOperationsGroupedByDrillerAndSection = factWellOperations .Select(o => new { Operation = o, schedules.FirstOrDefault(s => s.IdWell == o.IdWell && s.DrillStart <= o.DateStart && s.DrillEnd > o.DateStart && ( s.ShiftStart > s.ShiftEnd ) ^ (s.ShiftStart <= new TimeDto(o.DateStart.DateTime).MakeTimeOnly() && s.ShiftEnd > new TimeDto(o.DateStart.DateTime).MakeTimeOnly() )) ?.Driller, }) .Where(o => o.Driller != null) .GroupBy(o => new { o.Driller!.Id, o.Operation.IdWellSectionType }); var stats = detectedOperationsGroupedByDrillerAndSection.Select(group => new SlipsStatDto { DrillerName = $"{group.First().Driller!.Surname} {group.First().Driller!.Name} {group.First().Driller!.Patronymic}", SlipsCount = group.Count(), SlipsTimeInMinutes = group .Sum(y => (y.Operation.DateEnd - y.Operation.DateStart).TotalMinutes), SectionDepth = factWellOperationsGroupedByDrillerAndSection .Where(o => o.Key.Id == group.Key.Id) .Where(o => o.Key.IdWellSectionType == group.Key.IdWellSectionType) .Sum(o => o.Max(op => op.Operation.DepthEnd) - o.Min(op => op.Operation.DepthStart)), SectionCaption = group.First().Section.Caption, WellCount = group.GroupBy(g => g.IdWell).Count(), }); return stats; } }