using Microsoft.EntityFrameworkCore;
using DD.Persistence.Database.Model;
using DD.Persistence.Models;
using DD.Persistence.Models.Requests;

namespace DD.Persistence.Repository;

/// <summary>
/// класс с набором методов, необходимых для фильтрации записей
/// </summary>
public static class QueryBuilders
{
    public static IQueryable<TEntity> Apply<TEntity>(this IQueryable<TEntity> query, SectionPartRequest request)
        where TEntity : class, IWithSectionPart
    {
        if (request.IdSection.HasValue)
        {
            query = query.Where(e => e.IdSection == request.IdSection);
        }
        if (request.DepthStart.HasValue)
        {
            query = query.Where(e => e.DepthStart >= request.DepthStart);
        }
        if (request.DepthEnd.HasValue)
        {
            query = query.Where(e => e.DepthEnd <= request.DepthEnd);
        }

        return query;
    }

    public static IQueryable<TEntity> Apply<TEntity>(this IQueryable<TEntity> query, DateTimeOffset momentUtc)
    where TEntity : class, IChangeLog
    {
        momentUtc = momentUtc.ToUniversalTime();

        query = query
            .Where(e => e.Creation <= momentUtc)
            .Where(e => e.Obsolete == null || e.Obsolete >= momentUtc);

        return query;
    }


    public static async Task<PaginationContainer<TDto>> ApplyPagination<TEntity, TDto>(
        this IQueryable<TEntity> query,
        PaginationRequest request,
        Func<TEntity, TDto> Convert,
        CancellationToken token)
       where TEntity : class, IWithSectionPart
       where TDto : class
    {
        if (String.IsNullOrEmpty(request.SortSettings))
        {
            query = query
               .OrderBy(e => e.IdSection)
               .ThenBy(e => e.DepthStart)
               .ThenBy(e => e.DepthEnd);
        }
        else
        {
            query = query.SortBy(request.SortSettings);
        }

        var entities = await query
           .Skip(request.Skip)
           .Take(request.Take)
           .ToArrayAsync(token);

        var count = await query.CountAsync(token);
        var items = entities.Select(Convert);
        var result = new PaginationContainer<TDto>
        {
            Skip = request.Skip,
            Take = request.Take,
            Items = items,
            Count = count
        };

        return result;
    }
}