using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using AsbCloudApp.Data;
using AsbCloudApp.Data.SAUB;
using AsbCloudApp.Repositories;
using AsbCloudApp.Requests;
using AsbCloudApp.Services;

namespace AsbCloudInfrastructure.Services;

public class WellboreService : IWellboreService
{
   const string WellboreNameFormat = "Ствол {0}";
   private readonly IWellService wellService;
   private readonly IWellOperationRepository wellOperationRepository;
    private readonly ITelemetryDataCache<TelemetryDataSaubDto> telemetryDataCache;

    public WellboreService(
      IWellService wellService, 
      IWellOperationRepository wellOperationRepository, 
      ITelemetryDataCache<TelemetryDataSaubDto> telemetryDataCache)
   {
      this.wellService = wellService;
      this.wellOperationRepository = wellOperationRepository;
        this.telemetryDataCache = telemetryDataCache;
    }

   public async Task<IEnumerable<WellboreDto>> GetWellboresAsync(IEnumerable<int> idsWells,
      CancellationToken token)
   {
      var wellRequest = new WellRequest { Ids = idsWells };
      var wells = await wellService.GetAsync(wellRequest, token);

        var rowSections = await wellOperationRepository.GetSectionsAsync(idsWells, token);
      var groupedSections = rowSections
         .Where(section => section.IdType == 1)
         .GroupBy(s => s.IdWell);

      var wellbores = wells
            .SelectMany(well => {
            var wellSections = groupedSections.FirstOrDefault(group => group.Key == well.Id);
            if (wellSections is not null)
               return MakeWellboreBySections(wellSections, well);
            else
               return MakeWellboreDefault(well);
            })
         .OrderBy(w => w.Well.Id)
         .ThenBy(w => w.Id);

      return wellbores;
    }

    private IEnumerable<WellboreDto> MakeWellboreDefault(WellDto well)
    {
      var wellbore = new WellboreDto {
         Id = 1,
         Name = string.Format(WellboreNameFormat, 1),
         Well = well,
        };
      //if(well.)

      if(well.IdTelemetry is not null)
      {
         var dataCache = telemetryDataCache.GetOrDefaultFirstLast(well.IdTelemetry.Value);
         if (dataCache is not null)
         {
            wellbore.DateStart = dataCache.Value.First.DateTime;
            wellbore.DepthStart = dataCache.Value.First.WellDepth;

                wellbore.DateEnd = dataCache.Value.Last.DateTime;
                wellbore.DepthEnd = dataCache.Value.Last.WellDepth;
            }
      }

        return new[] { wellbore };
    }

    private IEnumerable<WellboreDto> MakeWellboreBySections(IEnumerable<SectionByOperationsDto> sections, WellDto well)
    {
      var orderedSections = sections.OrderBy(s => s.DateStart);
      var wellbores = new List<WellboreDto>();
      int wellboreId = 1;

      SectionByOperationsDto? preSection = null;
      WellboreDto? wellbore = null;

        foreach (var section in orderedSections)
      {
         if (wellbore is null || wellbore.DepthEnd > section.DepthStart)
         {
                wellbore = new WellboreDto
                {
                    Name = string.Format(WellboreNameFormat, wellboreId),
                    Id = wellboreId,
                    Well = well,

                    DateStart = section.DateStart,
                    DateEnd = section.DateEnd,
                    DepthStart = section.DepthStart,
                    DepthEnd = section.DepthEnd,
                };

                wellbores.Add(wellbore);
                wellboreId++;

            }
         else
         {
            wellbore.DepthEnd = section.DepthEnd;
            wellbore.DateEnd = section.DateEnd;
         }

            preSection = section;
        }

        if (wellbore is not null)
      {
            if (well.IdTelemetry is not null)
            {
                var dataCache = telemetryDataCache.GetOrDefaultFirstLast(well.IdTelemetry.Value);
                if (dataCache is not null)
                {
                    wellbore.DateEnd = dataCache.Value.Last.DateTime;
                    wellbore.DepthEnd = dataCache.Value.Last.WellDepth;
                }
            }
        }        

        return wellbores;
    }
}