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 groupedWellOperationsQuery = (from w in db.WellOperations where w.IdWell == idWell select w) .Include(w => w.WellSectionType) .GroupBy(op => op.IdWellSectionType); if (skip > 0) groupedWellOperationsQuery = groupedWellOperationsQuery.Skip(skip); var wellOperationsGroupedBySections = await groupedWellOperationsQuery .Take(take).ToListAsync(token) .ConfigureAwait(false); var result = new PaginationContainer { Skip = skip, Take = take, Count = wellOperationsGroupedBySections.Count }; if (!wellOperationsGroupedBySections.Any()) return result; // TODO: Подставить нормальные ID операций спускоа, подъема и т.д. 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().OperationCategory.Name, 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.Type == 0).Max(w => w.WellDepth), DepthFact: group.Where(o => o.Type == 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.Type == 0).Select(op => op.StartDate + TimeSpan.FromHours(op.DurationHours)).Max(), DurationMinPlan = group.Where(o => o.Type == 0).Min(i => i.StartDate), DurationMaxFact = group.Where(o => o.Type == 1).Select(op => op.StartDate + TimeSpan.FromHours(op.DurationHours)).Max(), DurationMinFact = group.Where(o => o.Type == 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 = groupedOperations.Select(g => new { DepthChangePlanSum = g.Where(o => o.Type == 0 && o.IdOperationCategory == 1) .Select((el, i) => i > 0 ? el.WellDepth - g.ElementAt(i - 1).WellDepth : 0).Sum(), DurationsPlanSum = g.Where(o => o.Type == 0 && o.IdOperationCategory == 1) .Select(el => el.DurationHours).Sum(), DepthChangeFactSum = g.Where(o => o.Type == 1 && o.IdOperationCategory == 1) .Select((el, i) => i > 0 ? el.WellDepth - g.ElementAt(i - 1).WellDepth : 0).Sum(), DurationsFactSum = g.Where(o => o.Type == 1 && o.IdOperationCategory == 1) .Select(el => el.DurationHours).Sum() }); return mechSpeedBase.Select(el => ( MechSpeedPlan: el.DepthChangePlanSum / el.DurationsPlanSum, MechSpeedFact: el.DepthChangeFactSum / el.DurationsFactSum )); } private static IEnumerable<(double BhaUpSpeedPlan, double BhaUpSpeedFact)> GetWellBhaUpSpeedPlanFact( IEnumerable> groupedOperations) { var bhaUpSpeedBase = GetParams(groupedOperations, 2); return bhaUpSpeedBase.Select(el => ( BhaUpSpeedPlan: el.DepthDifferencePlanSum / el.DurationDifferencePlanSum, BhaUpSpeedFact: el.DepthDifferenceFactSum / el.DurationDifferenceFactSum )); } private static IEnumerable<(double BhaDownSpeedPlan, double BhaDownSpeedFact)> GetWellBhaDownSpeedPlanFact( IEnumerable> groupedOperations) { var bhaDownSpeedBase = GetParams(groupedOperations, 3); return bhaDownSpeedBase.Select(el => ( BhaDownSpeedPlan: el.DepthDifferencePlanSum / el.DurationDifferencePlanSum, BhaDownSpeedFact: el.DepthDifferenceFactSum / el.DurationDifferenceFactSum )); } private static IEnumerable<(double CasingDownSpeedPlan, double CasingDownSpeedFact)> GetWellCasingDownPlanFact( IEnumerable> groupedOperations) { var casingDownBase = GetParams(groupedOperations, 4); return casingDownBase.Select(el => ( CasingDownSpeedPlan: el.DepthDifferencePlanSum / el.DurationDifferencePlanSum, CasingDownSpeedFact: el.DepthDifferenceFactSum / el.DurationDifferenceFactSum )).ToList(); } private static IEnumerable<(double DepthDifferencePlanSum, double DurationDifferencePlanSum, double DepthDifferenceFactSum, double DurationDifferenceFactSum)> GetParams(IEnumerable> items, int idOperationCategory) { return items.Select(g => ( DepthDifferencePlanSum: g.Where(o => o.Type == 0 && o.IdOperationCategory == idOperationCategory) .Select((el, i) => i > 0 ? el.WellDepth - g.ElementAt(i - 1).WellDepth : 0).Sum(), DurationDifferencePlanSum: g.Where(o => o.Type == 0 && o.IdOperationCategory == idOperationCategory) .Select(el => el.DurationHours).Sum(), DepthDifferenceFactSum: g.Where(o => o.Type == 1 && o.IdOperationCategory == idOperationCategory) .Select((el, i) => i > 0 ? el.WellDepth - g.ElementAt(i - 1).WellDepth : 0).Sum(), DurationDifferenceFactSum: g.Where(o => o.Type == 1 && o.IdOperationCategory == idOperationCategory) .Select(el => el.DurationHours).Sum() )); } private static IEnumerable<(double RouteSpeedPlan, double RouteSpeedFact)> GetWellRouteSpeedsPlanFact( IEnumerable> groupedOperations) { var bhaRaiseDecreaseCollection = new List<(WellOperation FirstDecreasePlan, WellOperation LastIncreasePlan, WellOperation FirstDecreaseFact, WellOperation LastIncreaseFact)>(); foreach (var group in groupedOperations) { var firstBhaPositionDecreasePlan = group.Any(o => o.IdOperationCategory == 5 && o.Type == 0) ? group.First(o => o.IdOperationCategory == 5 && o.Type == 0) : null; var lastBhaPositionIncreasePlan = group.Any(o => o.IdOperationCategory == 6 && o.Type == 0) ? group.First(o => o.IdOperationCategory == 5 && o.Type == 0) : null; var firstBhaPositionDecreaseFact = group.Any(o => o.IdOperationCategory == 5 && o.Type == 1) ? group.First(o => o.IdOperationCategory == 5 && o.Type == 1) : null; var lastBhaPositionIncreaseFact = group.Any(o => o.IdOperationCategory == 6 && o.Type == 1) ? group.First(o => o.IdOperationCategory == 5 && o.Type == 1) : null; bhaRaiseDecreaseCollection.Add((firstBhaPositionDecreasePlan, lastBhaPositionIncreasePlan, firstBhaPositionDecreaseFact, lastBhaPositionIncreaseFact)); } var routeSpeedsBase = bhaRaiseDecreaseCollection.Select(el => new // TODO: check value for null { RouteDepthPlan = el.FirstDecreasePlan.WellDepth - el.LastIncreasePlan.WellDepth, RouteDepthFact = el.FirstDecreaseFact.WellDepth - el.LastIncreaseFact.WellDepth, RouteDurationPlan = (el.LastIncreasePlan.StartDate + TimeSpan.FromHours(el.LastIncreasePlan.DurationHours) - el.FirstDecreasePlan.StartDate).TotalHours, RouteDurationFact = (el.LastIncreaseFact.StartDate + TimeSpan.FromHours(el.LastIncreaseFact.DurationHours) - el.FirstDecreaseFact.StartDate).TotalHours }); return routeSpeedsBase.Select(el => ( RouteSpeedPlan: el.RouteDepthPlan / el.RouteDurationPlan, RouteSpeedFact: el.RouteDepthFact / el.RouteDurationFact )).ToList(); } 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; } } }