using AsbCloudApp.Data; using AsbCloudApp.Data.SAUB; using AsbCloudApp.Data.WITS; using AsbCloudApp.Repositories; using AsbCloudApp.Requests; using AsbCloudApp.Services; using AsbCloudApp.Services.Subsystems; using AsbCloudInfrastructure.Background; using AsbCloudInfrastructure.Services.SAUB; using Mapster; using Microsoft.Extensions.DependencyInjection; using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; using AsbCloudApp.Data.ProcessMaps; using AsbCloudApp.IntegrationEvents; using AsbCloudApp.IntegrationEvents.Interfaces; namespace AsbCloudInfrastructure.Services; public class WellInfoService { public class WorkWellInfoUpdate : Work { public WorkWellInfoUpdate() : base("Well statistics update") { Timeout = TimeSpan.FromMinutes(30); } protected override async Task Action(string id, IServiceProvider services, Action onProgressCallback, CancellationToken token) { var wellService = services.GetRequiredService(); var operationsStatService = services.GetRequiredService(); var wellDrillingProcessMapRepository = services.GetRequiredService(); var subsystemOperationTimeService = services.GetRequiredService(); var telemetryDataSaubCache = services.GetRequiredService>(); var messageHub = services.GetRequiredService>(); var wells = await wellService.GetAllAsync(token); var activeWells = wells.Where(well => well.IdState == 1); var wellsIds = activeWells.Select(w => w.Id); var wellDrillingProcessMapRequests = wellsIds.Select(id => new WellDrillingProcessMapRequest { IdWell = id }); var wellDrillingProcessMaps = await wellDrillingProcessMapRepository.GetAsync(wellDrillingProcessMapRequests, token); var wellDepthByProcessMap = wellDrillingProcessMaps .GroupBy(p => p.IdWell) .Select(g => new { Id = g.Key, DepthEnd = g.Max(p => p.DepthEnd) }); var operationsStat = await operationsStatService.GetWellsStatAsync(wellsIds, token); var subsystemStat = await subsystemOperationTimeService .GetStatByActiveWells(wellsIds, token); subsystemStat = subsystemStat.ToArray(); var count = activeWells.Count(); var i = 0d; WellMapInfo = activeWells.Select(well => { var wellMapInfo = well.Adapt(); wellMapInfo.IdState = well.IdState; onProgressCallback($"Start updating info by well({well.Id}): {well.Caption}", i++ / count); double? currentDepth = null; TelemetryDataSaubDto? lastSaubTelemetry = null; if (well.IdTelemetry.HasValue) { wellMapInfo.IdTelemetry = well.IdTelemetry.Value; lastSaubTelemetry = telemetryDataSaubCache.GetLastOrDefault(well.IdTelemetry.Value); if (lastSaubTelemetry is not null) { currentDepth = lastSaubTelemetry.WellDepth; } } var wellOperationsStat = operationsStat.FirstOrDefault(s => s.Id == well.Id); var wellLastFactSection = wellOperationsStat?.Sections.LastOrDefault(s => s.Fact is not null); currentDepth ??= wellLastFactSection?.Fact?.WellDepthEnd; var wellProcessMaps = wellDrillingProcessMaps .Where(p => p.IdWell == well.Id) .OrderBy(p => p.DepthEnd); int? idSection = wellLastFactSection?.Id; WellDrillingProcessMapDto? wellDrillingProcessMap = null; if (idSection.HasValue) { wellDrillingProcessMap = wellProcessMaps.FirstOrDefault(p => p.IdWellSectionType == idSection); } else if (currentDepth.HasValue) { wellDrillingProcessMap = wellProcessMaps.FirstOrDefault(p => p.DepthStart <= currentDepth.Value && p.DepthEnd >= currentDepth.Value); } double? planTotalDepth = null; planTotalDepth = wellDepthByProcessMap.FirstOrDefault(p => p.Id == well.Id)?.DepthEnd; planTotalDepth ??= wellOperationsStat?.Total.Plan?.WellDepthEnd; wellMapInfo.Section = wellLastFactSection?.Caption; wellMapInfo.FirstFactOperationDateStart = wellOperationsStat?.Total.Fact?.Start ?? wellOperationsStat?.Total.Plan?.Start; wellMapInfo.LastPredictOperationDateEnd = wellOperationsStat?.Total.Plan?.End; wellMapInfo.AxialLoad = new() { Plan = wellDrillingProcessMap?.AxialLoad.Plan, Fact = lastSaubTelemetry?.AxialLoad }; wellMapInfo.TopDriveSpeed = new() { Plan = wellDrillingProcessMap?.TopDriveSpeed.Plan, Fact = lastSaubTelemetry?.RotorSpeed }; wellMapInfo.TopDriveTorque = new() { Plan = wellDrillingProcessMap?.TopDriveTorque.Plan, Fact = lastSaubTelemetry?.RotorTorque }; wellMapInfo.Pressure = new() { Plan = wellDrillingProcessMap?.Pressure.Plan, Fact = lastSaubTelemetry?.Pressure }; wellMapInfo.PressureSp = lastSaubTelemetry?.PressureSp; wellMapInfo.WellDepth = new() { Plan = planTotalDepth, Fact = currentDepth, }; wellMapInfo.ROP = new() { Plan = wellDrillingProcessMap?.RopPlan, Fact = wellOperationsStat?.Total.Fact?.Rop, }; wellMapInfo.RaceSpeed = new() { Plan = wellOperationsStat?.Total.Plan?.RouteSpeed, Fact = wellOperationsStat?.Total.Fact?.RouteSpeed, }; var wellSubsystemStat = subsystemStat.FirstOrDefault(s => s.Well.Id == well.Id); wellMapInfo.SaubUsage = wellSubsystemStat?.SubsystemAKB?.KUsage ?? 0d; wellMapInfo.SpinUsage = wellSubsystemStat?.SubsystemSpinMaster?.KUsage ?? 0d; wellMapInfo.TorqueKUsage = wellSubsystemStat?.SubsystemTorqueMaster?.KUsage ?? 0d; wellMapInfo.TvdLagDays = wellOperationsStat?.TvdLagDays; wellMapInfo.TvdDrillingDays = wellOperationsStat?.TvdDrillingDays; wellMapInfo.IdsCompanies = well.Companies.Select(c => c.Id); return wellMapInfo; }).ToArray(); var updateWellInfoEventTasks = wellsIds.Select(idWell => messageHub.HandleAsync(new UpdateWellInfoEvent(idWell), token)); await Task.WhenAll(updateWellInfoEventTasks); } } class WellMapInfoWithComanies : WellMapInfoDto { public int? IdTelemetry { get; set; } public IEnumerable IdsCompanies { get; set; } = null!; } private readonly TelemetryDataCache telemetryDataSaubCache; private readonly TelemetryDataCache telemetryDataSpinCache; private readonly IWitsRecordRepository witsRecord7Repository; private readonly IWitsRecordRepository witsRecord1Repository; private readonly IGtrRepository gtrRepository; private static IEnumerable WellMapInfo = Enumerable.Empty(); public WellInfoService( TelemetryDataCache telemetryDataSaubCache, TelemetryDataCache telemetryDataSpinCache, IWitsRecordRepository witsRecord7Repository, IWitsRecordRepository witsRecord1Repository, IGtrRepository gtrRepository) { this.telemetryDataSaubCache = telemetryDataSaubCache; this.telemetryDataSpinCache = telemetryDataSpinCache; this.witsRecord7Repository = witsRecord7Repository; this.witsRecord1Repository = witsRecord1Repository; this.gtrRepository = gtrRepository; } private WellMapInfoWithTelemetryStat Convert(WellMapInfoWithComanies wellInfo) { var result = wellInfo.Adapt(); if (wellInfo.IdTelemetry.HasValue) { var idTelemetry = wellInfo.IdTelemetry.Value; result.LastDataSaub = telemetryDataSaubCache.GetLastOrDefault(idTelemetry); result.LastDataSpin = telemetryDataSpinCache.GetLastOrDefault(idTelemetry); result.LastDataDdsDate = GetLastOrDefaultDdsTelemetry(idTelemetry); result.LastDataGtrDate = gtrRepository.GetLastData(wellInfo.Id) .MaxOrDefault(item => item.Date); result.LastDataDpcsDate = null; result.LastDataDpcsDate = null; } return result; } private DateTime? GetLastOrDefaultDdsTelemetry(int idTelemetry) { var lastDdsRecord1Date = witsRecord1Repository.GetLastOrDefault(idTelemetry)?.DateTime; var lastDdsRecord7Date = witsRecord7Repository.GetLastOrDefault(idTelemetry)?.DateTime; if (lastDdsRecord1Date.HasValue && lastDdsRecord7Date.HasValue) if (lastDdsRecord1Date.Value > lastDdsRecord7Date.Value) return lastDdsRecord1Date.Value; else return lastDdsRecord7Date.Value; return lastDdsRecord1Date ?? lastDdsRecord7Date; } public WellMapInfoWithTelemetryStat? FirstOrDefault(Func predicate) { var first = WellMapInfo.FirstOrDefault(predicate); if (first is WellMapInfoWithComanies wellMapInfoWithComanies) return Convert(wellMapInfoWithComanies); return null; } }