using AsbCloudApp.Data; using AsbCloudApp.Data.SAUB; using AsbCloudApp.Data.WITS; using AsbCloudApp.Repositories; using AsbCloudApp.Requests; using AsbCloudApp.Services; using AsbCloudInfrastructure.Background; 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 processMapPlanWellDrillingRepository = services.GetRequiredService>(); var subsystemService = 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 processMapPlanWellDrillingRequests = wellsIds.Select(id => new ProcessMapPlanRequest { IdWell = id }); var processMapPlanWellDrillings = await processMapPlanWellDrillingRepository.GetAsync(processMapPlanWellDrillingRequests, token); var wellDepthByProcessMap = processMapPlanWellDrillings .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 subsystemService .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.OrderBy(s => s.Fact?.WellDepthStart).LastOrDefault(s => s.Fact is not null); currentDepth ??= wellLastFactSection?.Fact?.WellDepthEnd; var wellProcessMaps = processMapPlanWellDrillings .Where(p => p.IdWell == well.Id) .OrderBy(p => p.DepthEnd); int? idSection = wellLastFactSection?.Id; ProcessMapPlanWellDrillingDto? processMapPlanWellDrilling = null; if (idSection.HasValue) { processMapPlanWellDrilling = wellProcessMaps.FirstOrDefault(p => p.IdWellSectionType == idSection); } else if (currentDepth.HasValue) { processMapPlanWellDrilling = 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 = processMapPlanWellDrilling?.AxialLoad.Plan, Fact = lastSaubTelemetry?.AxialLoad }; wellMapInfo.TopDriveSpeed = new() { Plan = processMapPlanWellDrilling?.TopDriveSpeed.Plan, Fact = lastSaubTelemetry?.RotorSpeed }; wellMapInfo.TopDriveTorque = new() { Plan = processMapPlanWellDrilling?.TopDriveTorque.Plan, Fact = lastSaubTelemetry?.RotorTorque }; wellMapInfo.Pressure = new() { Plan = processMapPlanWellDrilling?.Pressure.Plan, Fact = lastSaubTelemetry?.Pressure }; wellMapInfo.PressureSp = lastSaubTelemetry?.PressureSp; wellMapInfo.WellDepth = new() { Plan = planTotalDepth, Fact = currentDepth, }; wellMapInfo.ROP = new() { Plan = processMapPlanWellDrilling?.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?.SubsystemAPD?.KUsage ?? 0d; wellMapInfo.SpinUsage = wellSubsystemStat?.SubsystemOscillation?.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 ITelemetryDataCache telemetryDataSaubCache; private readonly ITelemetryDataCache telemetryDataSpinCache; private readonly IWitsRecordRepository witsRecord7Repository; private readonly IWitsRecordRepository witsRecord1Repository; private readonly IGtrRepository gtrRepository; private static IEnumerable WellMapInfo = Enumerable.Empty(); public WellInfoService( ITelemetryDataCache telemetryDataSaubCache, ITelemetryDataCache 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; } }