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

namespace AsbCloudInfrastructure.Services;


public class LimitingParameterService : ILimitingParameterService
{
    private readonly ILimitingParameterRepository limitingParameterRepository;
    private readonly IWellService wellService;
    private readonly  Dictionary<int, string> feedRegulatorData = new ()
    {
        { LimitingParameterDto.NoLimit, "Нет ограничения" },
        { LimitingParameterDto.RopPlan, "Скорость блока" },
        { LimitingParameterDto.Pressure, "Давление" },
        { LimitingParameterDto.AxialLoad, "Осевая нагрузка" },
        { LimitingParameterDto.RotorTorque, "Момент на роторе" }
    };

    public LimitingParameterService(ILimitingParameterRepository limitingParameterRepository,
        IWellService wellService)
    {
        this.limitingParameterRepository = limitingParameterRepository;
        this.wellService = wellService;
    }

    public async Task<IEnumerable<LimitingParameterDto>> GetStatAsync(LimitingParameterRequest request, CancellationToken token)
    {
        var well = await wellService.GetOrDefaultAsync(request.IdWell, token);
        if (well?.IdTelemetry is null || well.Timezone is null)
            return Enumerable.Empty<LimitingParameterDto>();

        var data = (await limitingParameterRepository.GetLimitingParametersAsync(request, well, token))
            .GroupBy(x => x.IdFeedRegulator);

        List<LimitingParameterDto> result = new List<LimitingParameterDto>(data.Count());
        foreach (var item in data)
        {
            var trimData = TrimLimitingParameters(item, request).ToArray();
            
            var allItemDepths = trimData.Sum(x => x.DepthEnd - x.DepthStart);
            var allItemDates = trimData.Sum(x => (x.DateEnd - x.DateStart).TotalMinutes);

            result.Add(new LimitingParameterDto
            {
                IdWell = well.Id,
                IdFeedRegulator = item.Key,
                Depth = allItemDepths,
                TotalMinutes = (float)allItemDates,
                NumberInclusions = item.Count(),
                NameFeedRegulator = feedRegulatorData.GetValueOrDefault(item.Key) ?? $"Id: {item.Key}"
            });
        }

        return result;
    }

    public Dictionary<int, string> GetLimitingParameteraNames() //TODO: Перенести получение ограничений в репозиторий
    {
        return feedRegulatorData;
    }

    private IEnumerable<LimitingParameterDataDto> TrimLimitingParameters(IEnumerable<LimitingParameterDataDto> data, LimitingParameterRequest request)
    {
        var result = data.Select((x) =>
        {
            if (request.GtDate.HasValue && x.DateStart < request.GtDate.Value)
            {
                x.DepthStart = GetDepth(request.GtDate.Value, x);
                x.DateStart = request.GtDate.Value;
            }
            if (request.LtDate.HasValue && x.DateEnd > request.LtDate.Value)
            {
                x.DepthEnd = GetDepth(request.LtDate.Value, x);
                x.DateEnd = request.LtDate.Value;
            }

            if (request.GtDepth.HasValue && x.DepthStart < request.GtDepth.Value)
            {
                x.DateStart = GetDate(request.GtDepth.Value, x);
                x.DepthStart = (float)request.GtDepth.Value;
            }
            if (request.LtDepth.HasValue && x.DepthEnd > request.LtDepth.Value)
            {
                x.DateEnd = GetDate(request.LtDepth.Value, x);
                x.DepthEnd = (float)request.LtDepth.Value;
            }
            return x;
        });
        return result;
    }

    private float GetDepth(DateTimeOffset date, LimitingParameterDataDto dto)
    {
        var a = (date - dto.DateStart).TotalSeconds;
        var b = (dto.DateEnd - dto.DateStart).TotalSeconds;
        var c = dto.DepthEnd - dto.DepthStart;
        var result = dto.DepthStart + (a / b) * c;
        return (float)result;
    }

    private DateTimeOffset GetDate(double depth, LimitingParameterDataDto dto)
    {
        var a = depth - dto.DepthStart;
        var b = dto.DepthEnd - dto.DepthStart;
        var c = (dto.DateEnd - dto.DateStart);
        var result = dto.DateStart + (a / b) * c;
        return result;
    }
}