using Microsoft.EntityFrameworkCore;
using StorageService.Domain.AggregatesModel.FolderAggregate;
using StorageService.Domain.SeedWork;

namespace StorageService.Infrastructure.Persistence.Repositories;

/// <summary>
/// EN: Repository implementation for Folder aggregate.
/// VI: Implementation repository cho Folder aggregate.
/// </summary>
public class FolderRepository : IFolderRepository
{
    private readonly StorageServiceContext _context;

    public FolderRepository(StorageServiceContext context)
    {
        _context = context ?? throw new ArgumentNullException(nameof(context));
    }

    public IUnitOfWork UnitOfWork => _context;

    /// <inheritdoc />
    public async Task<Folder?> GetByIdAsync(Guid id, CancellationToken cancellationToken = default)
    {
        return await _context.Folders
            .FirstOrDefaultAsync(x => x.Id == id && !x.IsDeleted, cancellationToken);
    }

    /// <inheritdoc />
    public async Task<IEnumerable<Folder>> GetRootFoldersAsync(string userId, CancellationToken cancellationToken = default)
    {
        return await _context.Folders
            .Where(x => x.UserId == userId && x.ParentId == null && !x.IsDeleted)
            .OrderBy(x => x.Name)
            .ToListAsync(cancellationToken);
    }

    /// <inheritdoc />
    public async Task<IEnumerable<Folder>> GetChildFoldersAsync(Guid parentId, CancellationToken cancellationToken = default)
    {
        return await _context.Folders
            .Where(x => x.ParentId == parentId && !x.IsDeleted)
            .OrderBy(x => x.Name)
            .ToListAsync(cancellationToken);
    }

    /// <inheritdoc />
    public async Task<Folder?> GetByPathAsync(string userId, string path, CancellationToken cancellationToken = default)
    {
        return await _context.Folders
            .FirstOrDefaultAsync(x => x.UserId == userId && x.Path == path && !x.IsDeleted, cancellationToken);
    }

    /// <inheritdoc />
    public async Task<IEnumerable<Folder>> GetDescendantsAsync(Guid folderId, CancellationToken cancellationToken = default)
    {
        var folder = await GetByIdAsync(folderId, cancellationToken);
        if (folder == null) return Enumerable.Empty<Folder>();

        // EN: Use path prefix to find all descendants / VI: Dùng path prefix để tìm tất cả con cháu
        return await _context.Folders
            .Where(x => x.Path.StartsWith(folder.Path) && x.Id != folderId && !x.IsDeleted)
            .OrderBy(x => x.Level)
            .ThenBy(x => x.Name)
            .ToListAsync(cancellationToken);
    }

    /// <inheritdoc />
    public async Task<Folder> AddAsync(Folder folder, CancellationToken cancellationToken = default)
    {
        await _context.Folders.AddAsync(folder, cancellationToken);
        return folder;
    }

    /// <inheritdoc />
    public void Update(Folder folder)
    {
        _context.Entry(folder).State = EntityState.Modified;
    }

    /// <inheritdoc />
    public async Task<bool> ExistsAsync(string userId, Guid? parentId, string name, CancellationToken cancellationToken = default)
    {
        return await _context.Folders
            .AnyAsync(x => x.UserId == userId && x.ParentId == parentId && x.Name == name && !x.IsDeleted, cancellationToken);
    }
}
