using AsbCloudApp.Data; using AsbCloudApp.Services; using AsbCloudDb.Model; using System; using System.Collections.Generic; using System.Linq; using Mapster; using Microsoft.EntityFrameworkCore; using System.Threading.Tasks; using System.Threading; using AsbCloudInfrastructure.Services.Cache; namespace AsbCloudInfrastructure.Services { public class WellSectionService: IWellSectionService { private readonly IAsbCloudDbContext db; private readonly CacheTable cachedSectionsTypes; public WellSectionService(IAsbCloudDbContext db, Cache.CacheDb cache) { this.db = db; cachedSectionsTypes = cache.GetCachedTable((DbContext)db); } public Task GetTypesAsync(CancellationToken token) => db.WellSectionTypes.Select(e => e.Caption).Distinct().AsNoTracking().ToArrayAsync(token); public async Task> GetSectionsByWellIdAsync(int idWell, int skip, int take, CancellationToken token = default) { var wellOperations = await (from w in db.WellOperations where w.IdWell == idWell select w) .Include(w => w.WellSectionType) .ToListAsync(token) .ConfigureAwait(false); var wellOperationsGroupedBySections = wellOperations .GroupBy(op => op.IdWellSectionType).ToList(); if (skip > 0) wellOperationsGroupedBySections = wellOperationsGroupedBySections.Skip(skip).ToList(); wellOperationsGroupedBySections = wellOperationsGroupedBySections.Take(take).ToList(); var result = new PaginationContainer { Skip = skip, Take = take, Count = wellOperationsGroupedBySections.Count }; if (!wellOperationsGroupedBySections.Any()) return result; var depthsPlanFactList = GetWellDepthPlanFact(wellOperationsGroupedBySections).ToList(); var durationsPlanFactList = GetWellDurationPlanFact(wellOperationsGroupedBySections).ToList(); var mechSpeedsList = GetWellMechSpeedPlanFact(wellOperationsGroupedBySections).ToList(); var bhaUpSpeedList = GetWellBhaUpSpeedPlanFact(wellOperationsGroupedBySections).ToList(); var bhaDownSpeedList = GetWellBhaDownSpeedPlanFact(wellOperationsGroupedBySections).ToList(); var casingDownList = GetWellCasingDownPlanFact(wellOperationsGroupedBySections).ToList(); var routeSpeeds = GetWellRouteSpeedsPlanFact(wellOperationsGroupedBySections).ToList(); var dtos = new List(); for(int i = 0; i < wellOperationsGroupedBySections.Count; i++) { var dto = new WellSectionDto { SectionType = wellOperationsGroupedBySections[i] .FirstOrDefault().WellSectionType.Caption, WellDepthPlan = depthsPlanFactList[i].DepthPlan, WellDepthFact = depthsPlanFactList[i].DepthFact, DurationPlan = durationsPlanFactList[i].DurationPlan, DurationFact = durationsPlanFactList[i].DurationFact, MechSpeedPlan = mechSpeedsList[i].MechSpeedPlan, MechSpeedFact = mechSpeedsList[i].MechSpeedFact, BhaUpSpeedPlan = bhaUpSpeedList[i].BhaUpSpeedPlan, BhaUpSpeedFact = bhaUpSpeedList[i].BhaUpSpeedFact, BhaDownSpeedPlan = bhaDownSpeedList[i].BhaDownSpeedPlan, BhaDownSpeedFact = bhaDownSpeedList[i].BhaDownSpeedFact, CasingDownSpeedPlan = casingDownList[i].CasingDownSpeedPlan, CasingDownSpeedFact = casingDownList[i].CasingDownSpeedFact, RouteSpeedPlan = routeSpeeds[i].RouteSpeedPlan, RouteSpeedFact = routeSpeeds[i].RouteSpeedFact }; dtos.Add(dto); } result.Items = dtos; return result; } public async Task GetSectionByWellIdAsync(int id, CancellationToken token = default) { var entity = await db.WellSections .Include(s => s.WellSectionType) .FirstOrDefaultAsync(e => e.Id == id, token) .ConfigureAwait(false); if (entity is null) return null; var dto = entity.Adapt(); dto.SectionType = entity.WellSectionType.Caption; return dto; } //public async Task InsertAsync(WellSectionDto item, int idWell, CancellationToken token = default) //{ // var sectionType = await GetWellSectionTypeFromCacheAndAssertAsync(item.SectionType); // var entity = item.Adapt(); // entity.Id = default; // entity.IdWell = idWell; // entity.IdWellSectionType = sectionType.Id; // var dbEntity = dbSet.Add(entity); // await context.SaveChangesAsync(token).ConfigureAwait(false); // var dto = dbEntity.Entity.Adapt(); // dto.SectionType = sectionType.Caption; // return dto; //} //public async Task> InsertRangeAsync(int idWell, IEnumerable items, CancellationToken token = default) //{ // var dbEntities = new Microsoft.EntityFrameworkCore.ChangeTracking.EntityEntry[items.Count()]; // for (int i = 0; i < dbEntities.Length; i++) // { // var sectionType = await GetWellSectionTypeFromCacheAndAssertAsync(items.ElementAt(i).SectionType, token); // var item = items.ElementAt(i).Adapt(); // item.IdWell = idWell; // item.IdWellSectionType = sectionType.Id; // dbEntities[i] = dbSet.Add(item); // } // await context.SaveChangesAsync(token).ConfigureAwait(false); // var dtos = dbEntities.Select((e) => { // var dto = e.Entity.Adapt(); // var sectionType = cachedSectionsTypes.FirstOrDefault(s => s.Id == e.Entity.IdWellSectionType); // dto.SectionType = sectionType.Caption; // return dto; // }); // return dtos; //} //public async Task UpdateAsync(int idWell, int idSection, WellSectionDto item, CancellationToken token = default) //{ // var sectionType = await GetWellSectionTypeFromCacheAndAssertAsync(item.SectionType, token) // .ConfigureAwait(false); // var entity = item.Adapt(); // entity.Id = idSection; // entity.IdWell = idWell; // entity.IdWellSectionType = sectionType.Id; // var dbEntity = dbSet.Update(entity); // await context.SaveChangesAsync(token).ConfigureAwait(false); // var dto = dbEntity.Entity.Adapt(); // dto.SectionType = sectionType.Caption; // return dto; //} //public Task DeleteAsync(IEnumerable ids, CancellationToken token = default) //{ // var entities = dbSet.Where(e => ids.Contains(e.Id)); // dbSet.RemoveRange(entities); // return context.SaveChangesAsync(token); //} private static IEnumerable<(double DepthPlan, double DepthFact)> GetWellDepthPlanFact( IEnumerable> groupedOperations) { return groupedOperations .Select(group => ( DepthPlan: group.Where(o => o.IdType == 0).Max(w => w.WellDepth), DepthFact: group.Where(o => o.IdType == 1).Max(w => w.WellDepth) )); } private static IEnumerable<(double DurationPlan, double DurationFact)> GetWellDurationPlanFact( IEnumerable> groupedOperations) { var durationsPlanFactsBase = groupedOperations.Select(group => new { DurationMaxPlan = group.Where(o => o.IdType == 0).Select(op => op.StartDate + TimeSpan.FromHours(op.DurationHours)).Max(), DurationMinPlan = group.Where(o => o.IdType == 0).Min(i => i.StartDate), DurationMaxFact = group.Where(o => o.IdType == 1).Select(op => op.StartDate + TimeSpan.FromHours(op.DurationHours)).Max(), DurationMinFact = group.Where(o => o.IdType == 1).Min(i => i.StartDate) }); return durationsPlanFactsBase.Select(o => ( DurationPlan: (o.DurationMaxPlan - o.DurationMinPlan).TotalHours, DurationFact: (o.DurationMaxFact - o.DurationMinFact).TotalHours )); } private static IEnumerable<(double MechSpeedPlan, double MechSpeedFact)> GetWellMechSpeedPlanFact( IEnumerable> groupedOperations) { var mechSpeedBase = GetParams(groupedOperations, 1001); return CalculateResult(mechSpeedBase); } private static IEnumerable<(double BhaDownSpeedPlan, double BhaDownSpeedFact)> GetWellBhaDownSpeedPlanFact( IEnumerable> groupedOperations) { var bhaDownSpeedBase = GetParams(groupedOperations, 1046); return CalculateResult(bhaDownSpeedBase); } private static IEnumerable<(double BhaUpSpeedPlan, double BhaUpSpeedFact)> GetWellBhaUpSpeedPlanFact( IEnumerable> groupedOperations) { var bhaUpSpeedBase = GetParams(groupedOperations, 1047); return CalculateResult(bhaUpSpeedBase); } private static IEnumerable<(double CasingDownSpeedPlan, double CasingDownSpeedFact)> GetWellCasingDownPlanFact( IEnumerable> groupedOperations) { var casingDownBase = GetParams(groupedOperations, 1048); return CalculateResult(casingDownBase); } private static IEnumerable<(double RouteSpeedPlan, double RouteSpeedFact)> GetWellRouteSpeedsPlanFact( IEnumerable> groupedOperations) { var bhaRaiseDecreaseCollection = new List<(WellOperation FirstBhaPositionDecreasePlan, WellOperation LastBhaPositionIncreasePlan, WellOperation FirstBhaPositionDecreaseFact, WellOperation LastBhaPositionIncreaseFact)>(); foreach (var group in groupedOperations) { var firstBhaPositionDecreasePlan = group.Any(o => o.IdCategory == 1046 && o.IdType == 0) ? group.First(o => o.IdCategory == 1046 && o.IdType == 0) : null; var lastBhaPositionIncreasePlan = group.Any(o => o.IdCategory == 1047 && o.IdType == 0) ? group.Last(o => o.IdCategory == 1047 && o.IdType == 0) : null; var firstBhaPositionDecreaseFact = group.Any(o => o.IdCategory == 1046 && o.IdType == 1) ? group.First(o => o.IdCategory == 1046 && o.IdType == 1) : null; var lastBhaPositionIncreaseFact = group.Any(o => o.IdCategory == 1047 && o.IdType == 1) ? group.Last(o => o.IdCategory == 1047 && o.IdType == 1) : null; bhaRaiseDecreaseCollection.Add((firstBhaPositionDecreasePlan, lastBhaPositionIncreasePlan, firstBhaPositionDecreaseFact, lastBhaPositionIncreaseFact)); } var routeSpeedsBase = bhaRaiseDecreaseCollection.Select(el => ( RouteDepthPlan: (el.LastBhaPositionIncreasePlan?.WellDepth - el.FirstBhaPositionDecreasePlan?.WellDepth) ?? 0, RouteDepthFact: (el.LastBhaPositionIncreaseFact?.WellDepth - el.FirstBhaPositionDecreaseFact?.WellDepth) ?? 0, RouteDurationPlan: (el.LastBhaPositionIncreasePlan?.StartDate + TimeSpan.FromHours(el.LastBhaPositionIncreasePlan?.DurationHours ?? 0) - el.FirstBhaPositionDecreasePlan?.StartDate)?.TotalHours ?? 0, RouteDurationFact: (el.LastBhaPositionIncreaseFact?.StartDate + TimeSpan.FromHours(el.LastBhaPositionIncreaseFact?.DurationHours ?? 0) - el.FirstBhaPositionDecreaseFact?.StartDate)?.TotalHours ?? 0 )); return CalculateResult(routeSpeedsBase); } private static IEnumerable<(double DepthDifferencePlanSum, double DurationDifferencePlanSum, double DepthDifferenceFactSum, double DurationDifferenceFactSum)> GetParams(IEnumerable> items, int IdCategory) { return items.Select(g => ( DepthDifferencePlanSum: g.Where(o => o.IdType == 0 && o.IdCategory == IdCategory) .Select((el, i) => i > 0 ? el.WellDepth - g.ElementAt(i - 1).WellDepth : 0).Sum(), DurationDifferencePlanSum: g.Where(o => o.IdType == 0 && o.IdCategory == IdCategory) .Select(el => el.DurationHours).Sum(), DepthDifferenceFactSum: g.Where(o => o.IdType == 1 && o.IdCategory == IdCategory) .Select((el, i) => i > 0 ? el.WellDepth - g.ElementAt(i - 1).WellDepth : 0).Sum(), DurationDifferenceFactSum: g.Where(o => o.IdType == 1 && o.IdCategory == IdCategory) .Select(el => el.DurationHours).Sum() )); } private static IEnumerable<(double DataPlan, double DataFact)> CalculateResult(IEnumerable<(double Item1Plan, double Item1Fact, double Item2Plan, double Item2Fact)> rawData) { return rawData.Select(el => ( RouteSpeedPlan: (el.Item1Plan / el.Item2Plan) is double.NaN ? 0 : (el.Item1Plan / el.Item2Plan), RouteSpeedFact: (el.Item1Fact / el.Item2Fact) is double.NaN ? 0 : (el.Item1Fact / el.Item2Fact) )); } private async Task GetWellSectionTypeFromCacheAndAssertAsync(string wellSectionType, CancellationToken token = default) { if (string.IsNullOrEmpty(wellSectionType)) throw new ArgumentException("Тип секции должен быть указан", nameof(WellSectionDto.SectionType)); var sectionType = await cachedSectionsTypes .FirstOrDefaultAsync(s => s.Caption.Equals(wellSectionType, StringComparison.OrdinalIgnoreCase), token) .ConfigureAwait(false); if (sectionType is null) { throw new ArgumentException($"Тип секции '{wellSectionType}' отсутствует в справочнике", nameof(WellSectionDto.SectionType)); //sectionType = await cachedSectionsTypes.InsertAsync(new WellSectionType { Caption = item.SectionType}, token); } return sectionType; } } }