using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using AsbCloudApp.Data.ProcessMaps;
using AsbCloudApp.Exceptions;
using AsbCloudApp.Repositories;
using AsbCloudApp.Requests;
using AsbCloudApp.Services;
using AsbCloudDb.Model;
using AsbCloudDb.Model.ProcessMaps;
using Microsoft.EntityFrameworkCore;

namespace AsbCloudInfrastructure.Repository;

public class ProcessMapPlanRepository<TDto, TEntity> : CrudWellRelatedRepositoryBase<TDto, TEntity>,
    IProcessMapPlanRepository<TDto>
    where TDto : ProcessMapPlanBaseDto
    where TEntity : ProcessMapBase
{
    private readonly IWellService wellService;

    public ProcessMapPlanRepository(IAsbCloudDbContext context, IWellService wellService)
       : base(context, dbSet =>
          dbSet
             .Include(p => p.WellSectionType)
             .Include(p => p.Well))
    {
        this.wellService = wellService;
    }

    public async Task<IEnumerable<TDto>> GetAsync(IEnumerable<ProcessMapPlanRequest> requests, CancellationToken cancellationToken)
    {
        var query = BuildQuery(requests);

        var entities = await query.ToArrayAsync(cancellationToken);

        return entities.Select(Convert);
    }

    public Task<int> RemoveByWellAsync(int idWell)
    {
        var query = GetQuery().Where(x => x.IdWell == idWell);

        dbSet.RemoveRange(query);

        return dbContext.SaveChangesAsync(CancellationToken.None);
    }

    private IQueryable<TEntity> BuildQuery(IEnumerable<ProcessMapPlanRequest> requests)
    {
        var queries = requests
            .Select(request => BuildQuery(request))
            .ToArray();
     
        var query = queries.FirstOrDefault()
            ?? throw new ArgumentInvalidException(nameof(requests), "Пустые запросы недопустимы");

        for ( var i = 1; i < queries.Length; i++)
            query = query.Union(queries[i]);

        query = query
            .Distinct()
            .OrderBy(e => e.DepthStart)
            .ThenBy(e => e.Id)
            .AsNoTracking();

        return query;
    }

    private IQueryable<TEntity> BuildQuery(ProcessMapPlanRequest request)
    {
        var query = GetQuery();
         
        query = query.Where(p => p.IdWell == request.IdWell);

        if (request.IdWellSectionType is not null)
            query = query.Where(p => p.IdWellSectionType == request.IdWellSectionType);

        if (request.UpdateFrom is not null)
        {
            var timezone = wellService.GetTimezone(request.IdWell);
            var updateFromUtc = request.UpdateFrom?.ToUtcDateTimeOffset(timezone.Hours);

            query = query.Where(p => p.LastUpdate >= updateFromUtc);
        }
        return query;
    }
}