using AsbCloudApp.Data; using AsbCloudApp.Data.ProcessMap; using AsbCloudApp.Data.SAUB; using AsbCloudApp.Data.WITS; using AsbCloudApp.Repositories; using AsbCloudApp.Requests; using AsbCloudApp.Services; using AsbCloudApp.Services.Subsystems; using AsbCloudDb.Model; 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.IntegrationEvents; using AsbCloudApp.IntegrationEvents.Events; namespace AsbCloudInfrastructure.Services { public class WellInfoService { class WellMapInfoWithComanies : WellMapInfoDto { public int? IdTelemetry { get; set; } public IEnumerable IdsCompanies { get; set; } = null!; } private const string workId = "Well statistics update"; private static readonly TimeSpan workPeriod = TimeSpan.FromMinutes(30); 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; } public static WorkPeriodic MakeWork() { var workPeriodic = new WorkPeriodic(workId, WorkAction, workPeriod) { Timeout = TimeSpan.FromMinutes(30) }; return workPeriodic; } private static async Task WorkAction(string workName, IServiceProvider serviceProvider, CancellationToken token) { var db = serviceProvider.GetRequiredService(); var wellService = serviceProvider.GetRequiredService(); var operationsStatService = serviceProvider.GetRequiredService(); var processMapRepository = serviceProvider.GetRequiredService(); var subsystemOperationTimeService = serviceProvider.GetRequiredService(); var telemetryDataSaubCache = serviceProvider.GetRequiredService>(); var messageHub = serviceProvider.GetRequiredService>(); var activeWells = await wellService.GetAsync(new() {IdState = 1}, token); IEnumerable activeWellsIds = activeWells .Select(w => w.Id); var idTelemetries = activeWells .Where(w => w.IdTelemetry != null) .Select(t => t.IdTelemetry); var processMapRequests = activeWellsIds.Select(id => new ProcessMapRequest { IdWell = id }); var processMaps = await processMapRepository.GetProcessMapAsync(processMapRequests, token); var wellDepthByProcessMap = processMaps .GroupBy(p => p.IdWell) .Select(g => new { Id = g.Key, DepthEnd = g.Max(p => p.DepthEnd) }); var operationsStat = await operationsStatService.GetWellsStatAsync(activeWellsIds, token); var subsystemStat = await subsystemOperationTimeService.GetStatByActiveWells(activeWellsIds, token); WellMapInfo = activeWells.Select(well => { var wellMapInfo = well.Adapt(); wellMapInfo.IdState = well.IdState; double? currentDepth = null; if (well.IdTelemetry.HasValue) { wellMapInfo.IdTelemetry = well.IdTelemetry.Value; var 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 = processMaps .Where(p => p.IdWell == well.Id) .OrderBy(p => p.DepthEnd); int? idSection = wellLastFactSection?.Id; ProcessMapPlanDto? welllProcessMap = null; if (idSection.HasValue) { welllProcessMap = wellProcessMaps.FirstOrDefault(p => p.IdWellSectionType == idSection); } else if(currentDepth.HasValue) { welllProcessMap = wellProcessMaps.FirstOrDefault(p => p.DepthStart <= currentDepth.Value && p.DepthEnd >= currentDepth.Value); idSection ??= welllProcessMap?.IdWellSectionType; } double? planTotalDepth = null; planTotalDepth = wellDepthByProcessMap.FirstOrDefault(p => p.Id == well.Id)?.DepthEnd; planTotalDepth ??= wellOperationsStat?.Total.Plan?.WellDepthEnd; wellMapInfo.FirstFactOperationDateStart = wellOperationsStat?.Total.Fact?.Start ?? wellOperationsStat?.Total.Plan?.Start; wellMapInfo.LastPredictOperationDateEnd = wellOperationsStat?.Total.Plan?.End; wellMapInfo.WellDepth = new() { Plan = planTotalDepth, Fact = currentDepth, }; wellMapInfo.ROP = new() { Plan = welllProcessMap?.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.TvdLagPercent = wellOperationsStat?.TvdLagPercent ?? 0d; wellMapInfo.IdsCompanies = well.Companies.Select(c => c.Id); return wellMapInfo; }).ToArray(); foreach (var idWell in activeWellsIds) { await messageHub.HandleAsync(new WellInfoUpdaterEvent(idWell), token); } } 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; } } }