using Microsoft.EntityFrameworkCore;
using Modules.User.Application.Models;
using Modules.User.Application.Models.Access;
using Modules.User.Application.Repositories;
using Modules.User.Database.Database;

namespace Modules.User.Database.Queries;

public sealed class RoleQueries(UserDbContext context) : IRoleQueries
{
    public async Task<PagedData<Role>> GetRolesAsync(RoleListFilter filter, CancellationToken cancellationToken = default)
    {
        var query = context.Roles
            .AsNoTracking()
            .Include(r => r.Permissions)
            .AsQueryable();

        if (filter.Ids.Any())
            query = query.Where(r => filter.Ids.Contains(r.Id));

        if (!string.IsNullOrWhiteSpace(filter.NamesStartWith))
            query = query.Where(r => r.Name.StartsWith(filter.NamesStartWith));

        if (filter.CreatedAtFrom.HasValue)
            query = query.Where(r => r.CreationDate >= filter.CreatedAtFrom.Value.UtcDateTime);

        if (filter.CreatedAtTo.HasValue)
            query = query.Where(r => r.CreationDate <= filter.CreatedAtTo.Value.UtcDateTime);
        
        var count = await query.CountAsync(cancellationToken);
        var take = filter?.ItemsOnPage > 0 ? filter.ItemsOnPage : 10;
        var pagesCount = (int)Math.Ceiling((decimal)count / take);
        var page = filter?.Page ?? 1;
        if (page < 1) page = 1;
        if (page > pagesCount) page = pagesCount > 0 ? pagesCount : 1;
        var skip = (page - 1) * take;

        var items = await query
            .OrderBy(r => r.Name)
            .Skip(skip)
            .Take(take)
            .Select(r => new Role
            {
                Id = r.Id,
                Name = r.Name,
                Description = r.Description,
                Permissions = r.Permissions.Select(p => new PermissionShort
                {
                    Id = p.Id,
                    Name = p.Name,
                    Description = p.Description
                }).ToList()
            })
            .ToListAsync(cancellationToken);

        return new PagedData<Role>
        {
            Page = page,
            ItemsOnPage = take,
            ItemsCount = count,
            PagesCount = pagesCount,
            Items = items
        };
    }

    public async Task<IEnumerable<RoleShort>> GetRolesShortAsync(CancellationToken cancellationToken = default)
    {
        return await context.Roles
            .Select(q => new RoleShort { Id = q.Id, Name = q.Name, })
            .AsNoTracking()
            .ToListAsync(cancellationToken);
    }

    public async Task<RoleDetail?> GetDetailByIdAsync(int roleId, CancellationToken cancellationToken = default)
    {
        return await context.Roles
            .AsNoTracking()
            .Include(r => r.Permissions)
            .Where(r => r.Id == roleId)
            .Select(r => new RoleDetail
            {
                Id = r.Id,
                Name = r.Name,
                Description = r.Description,
                Permissions = r.Permissions
                    .Select(p => new Permission
                    {
                        Id = p.Id,
                        Name = p.Name,
                        Code = p.Code,
                        Description = p.Description,
                    }).ToList(),
                CreatedAt = r.CreationDate,
            })
            .FirstOrDefaultAsync(cancellationToken);
    }
}
