using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
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;
using AsbCloudDb;
using AsbCloudDb.Model;
using Mapster;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Memory;

namespace AsbCloudInfrastructure.Repository;

public class NotificationRepository : CrudCacheRepositoryBase<NotificationDto, Notification>, INotificationRepository
{
	private static IQueryable<Notification> MakeQueryNotification(DbSet<Notification> dbSet)
		=> dbSet.Include(n => n.NotificationCategory)
			.AsNoTracking();

	public NotificationRepository(IAsbCloudDbContext dbContext, IMemoryCache memoryCache)
		: base(dbContext, memoryCache, MakeQueryNotification)
	{
	}

	public async Task<int> UpdateRangeAsync(IEnumerable<NotificationDto> notifications, CancellationToken cancellationToken)
	{
		if (!notifications.Any())
			return 0;
		
		var ids = notifications.Select(d => d.Id).ToArray();
		
		var existingEntities = await dbSet
			.Where(d => ids.Contains(d.Id))
			.AsNoTracking()
			.Select(d => d.Id)
			.ToArrayAsync(cancellationToken);

		if (ids.Length > existingEntities.Length)
			return ICrudRepository<SetpointsRequestDto>.ErrorIdNotFound;

		var entities = notifications.Select(Convert);

		dbContext.Notifications.UpdateRange(entities);

		var result = await dbContext.SaveChangesAsync(cancellationToken);
		DropCache();
		return result;
	}

	public async Task<PaginationContainer<NotificationDto>> GetNotificationsAsync(int idUser,
		NotificationRequest request,
		CancellationToken cancellationToken)
	{
		var skip = request.Skip ?? 0;
		var take = request.Take ?? 10;

		var query = BuildQuery(idUser, request);

		var result = new PaginationContainer<NotificationDto>()
		{
			Skip = skip,
			Take = take,
			Count = await query.CountAsync(cancellationToken),
		};

		if (result.Count < skip)
			return result;

		result.Items = await query
			.SortBy(request.SortFields)
			.Skip(skip)
			.Take(take)
			.AsNoTracking()
			.Select(x => x.Adapt<NotificationDto>())
			.ToArrayAsync(cancellationToken);

		return result;
	}

	private IQueryable<Notification> BuildQuery(int idUser, 
		NotificationRequest request)
	{
		var query = dbContext.Notifications
			.Include(x => x.NotificationCategory)
			.Where(n => n.IdUser == idUser);

		if (request.IsSent.HasValue)			
		{
			if(request.IsSent.Value)
                query = query.Where(n => n.SentDate != null);
            else
                query = query.Where(n => n.SentDate == null);
        }

		if (request.IdTransportType.HasValue)
			query = query.Where(n => n.IdTransportType == request.IdTransportType);

		return query;
	}
}