using AsbCloudApp.Data; using AsbCloudApp.Data.DetectedOperation; using AsbCloudApp.Data.Subsystems; using AsbCloudApp.Exceptions; using AsbCloudApp.Requests; using AsbCloudApp.Services; using AsbCloudDb.Model; using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; using AsbCloudInfrastructure.Services.DetectOperations; namespace AsbCloudInfrastructure.Services.Subsystems; internal class SubsystemService : ISubsystemService { private const int IdSubsystemAPD = 1; private const int IdSubsystemAPDRotor = 11; private const int IdSubsystemAPDSlide = 12; private const int IdSubsystemOscillation = 65536; private readonly ICrudRepository subsystemRepository; private readonly IWellService wellService; private readonly IDetectedOperationService detectedOperationService; private readonly ITelemetryDataSaubService telemetryDataSaubService; public SubsystemService(ICrudRepository subsystemRepository, IWellService wellService, IDetectedOperationService detectedOperationService, ITelemetryDataSaubService telemetryDataSaubService) { this.wellService = wellService; this.subsystemRepository = subsystemRepository; this.detectedOperationService = detectedOperationService; this.telemetryDataSaubService = telemetryDataSaubService; } public async Task> GetStatAsync(SubsystemRequest request, CancellationToken token) { var well = await wellService.GetOrDefaultAsync(request.IdWell, token) ?? throw new ArgumentInvalidException(nameof(request.IdWell), $"Well Id: {request.IdWell} does not exist"); var detectedOperationSummaryRequest = new DetectedOperationSummaryRequest { IdsTelemetries = new[] { well.IdTelemetry!.Value }, IdsOperationCategories = WellOperationCategory.MechanicalDrillingSubIds, GeDateStart = request.GeDate, LeDateStart = request.LeDate, GeDepthStart = request.GeDepth, LeDepthStart = request.LeDepth, }; var operations = await detectedOperationService.GetOperationSummaryAsync(detectedOperationSummaryRequest, token); if (!operations.Any()) return Enumerable.Empty(); var stat = await CalcStatAsync(operations, token); return stat; } public async Task> GetStatByActiveWells(int idCompany, DateTime? gtDate, DateTime? ltDate, CancellationToken token) { var activeWells = await wellService.GetAsync(new() { IdCompany = idCompany, IdState = 1 }, token); var result = await GetStatAsync(activeWells, gtDate, ltDate, token); return result; } public async Task> GetStatByActiveWells(IEnumerable wellIds, CancellationToken token) { var activeWells = await wellService.GetAsync(new() { Ids = wellIds, IdState = 1 }, token); var result = await GetStatAsync(activeWells, null, null, token); return result; } private async Task> CalcStatAsync(IEnumerable operations, CancellationToken token) { var subsystems = await subsystemRepository.GetAllAsync(token); var groupedOperations = operations .GroupBy(o => o.IdCategory); var stat = groupedOperations.Select(groupOperations => { var idSubsystem = groupOperations.Key switch { WellOperationCategory.IdRotor => IdSubsystemAPDRotor, WellOperationCategory.IdSlide => IdSubsystemAPDSlide, _ => throw new ArgumentException($"IdCategory: {groupOperations.Key} does not supported in this method", nameof(groupOperations.Key)), }; var operationsWithEnableSubsystems = groupOperations.Where(o => (EnabledSubsystemsFlags.AutoRotor | EnabledSubsystemsFlags.AutoSlide | EnabledSubsystemsFlags.AutoOscillation).HasEnabledSubsystems(o.EnabledSubsystems)); var subsystemStat = new SubsystemStatDto { IdSubsystem = idSubsystem, SubsystemName = subsystems.FirstOrDefault(s => s.Id == idSubsystem)?.Name ?? "unknown", UsedTimeHours = operationsWithEnableSubsystems.Sum(o => o.SumDurationHours), SumOperationDepthInterval = groupOperations.Sum(o => o.SumDepthIntervals), SumOperationDurationHours = groupOperations.Sum(o => o.SumDurationHours), SumDepthInterval = operationsWithEnableSubsystems.Sum(o => o.SumDepthIntervals), OperationCount = operationsWithEnableSubsystems.Sum(o => o.Count), }; subsystemStat.KUsage = subsystemStat.SumDepthInterval / subsystemStat.SumOperationDepthInterval; return subsystemStat; }); var apdSlidePart = stat.FirstOrDefault(s => s.IdSubsystem == IdSubsystemAPDSlide); if (apdSlidePart is not null) { var operationsWithOscillation = operations.Where(o => EnabledSubsystemsFlags.AutoOscillation.HasEnabledSubsystems(o.EnabledSubsystems)); var spinMaster = new SubsystemStatDto { IdSubsystem = IdSubsystemOscillation, SubsystemName = subsystems.FirstOrDefault(s => s.Id == IdSubsystemOscillation)?.Name ?? "unknown", UsedTimeHours = operationsWithOscillation.Sum(o => o.SumDurationHours), SumOperationDepthInterval = apdSlidePart.SumOperationDepthInterval, SumOperationDurationHours = apdSlidePart.SumOperationDurationHours, SumDepthInterval = operationsWithOscillation.Sum(o => o.SumDepthIntervals), OperationCount = operationsWithOscillation.Sum(s => s.Count) }; spinMaster.KUsage = spinMaster.SumDepthInterval / spinMaster.SumOperationDepthInterval; stat = stat.Append(spinMaster); } var apdParts = stat.Where(s => s.IdSubsystem is IdSubsystemAPDRotor or IdSubsystemAPDSlide); if (!apdParts.Any()) return stat; var apdSum = new SubsystemStatDto { IdSubsystem = IdSubsystemAPD, SubsystemName = "АПД", UsedTimeHours = apdParts.Sum(part => part.UsedTimeHours), SumOperationDepthInterval = apdParts.Sum(part => part.SumOperationDepthInterval), SumOperationDurationHours = apdParts.Sum(part => part.SumOperationDurationHours), SumDepthInterval = apdParts.Sum(part => part.SumDepthInterval), OperationCount = apdParts.Sum(part => part.OperationCount), }; apdSum.KUsage = apdSum.SumDepthInterval / apdSum.SumOperationDepthInterval; stat = stat.Append(apdSum).OrderBy(m => m.IdSubsystem); return stat; } private async Task> GetStatAsync(IEnumerable wells, DateTime? gtDate, DateTime? ltDate, CancellationToken token) { if (!wells.Any()) return Enumerable.Empty(); var idsTelemetries = wells .Where(w => w.IdTelemetry is not null) .Select(w => w.IdTelemetry!.Value) .Distinct(); var wellsStat = new List(); foreach (var well in wells) { var hoursOffset = well.Timezone.Hours; var dateRange = telemetryDataSaubService.GetRange(well.Id); var beginUTC = gtDate.HasValue ? gtDate.Value.ToUtcDateTimeOffset(hoursOffset) : dateRange.From.ToUtcDateTimeOffset(hoursOffset); var endUTC = ltDate.HasValue ? ltDate.Value.ToUtcDateTimeOffset(hoursOffset) : dateRange.To.ToUtcDateTimeOffset(hoursOffset); var operations = await detectedOperationService .GetOperationSummaryAsync(new() { IdsTelemetries = idsTelemetries, IdsOperationCategories = WellOperationCategory.MechanicalDrillingSubIds, GeDateStart = beginUTC, LeDateEnd = endUTC, }, token); var wellStat = new SubsystemActiveWellStatDto { Well = well }; var telemetryOperations = operations.Where(o => o.IdTelemetry == well.IdTelemetry); if (!telemetryOperations.Any()) continue; var subsystemStat = await CalcStatAsync(telemetryOperations, token); if (!subsystemStat.Any()) continue; wellStat.SubsystemAPD = subsystemStat.FirstOrDefault(s => s.IdSubsystem == IdSubsystemAPD); wellStat.SubsystemOscillation = subsystemStat.FirstOrDefault(s => s.IdSubsystem == IdSubsystemOscillation); } return wellsStat; } }