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

namespace StorageService.Infrastructure.Persistence.Repositories;

/// <summary>
/// EN: Repository implementation for StorageFile aggregate.
/// VI: Repository implementation cho StorageFile aggregate.
/// </summary>
public class FileRepository : IFileRepository
{
    private readonly StorageServiceContext _context;

    public IUnitOfWork UnitOfWork => _context;

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

    /// <inheritdoc />
    public async Task<StorageFile> AddAsync(StorageFile file, CancellationToken cancellationToken = default)
    {
        var entry = await _context.StorageFiles.AddAsync(file, cancellationToken);
        return entry.Entity;
    }

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

    /// <inheritdoc />
    public async Task<StorageFile?> GetByIdAsync(Guid id, CancellationToken cancellationToken = default)
    {
        return await _context.StorageFiles
            .FirstOrDefaultAsync(f => f.Id == id, cancellationToken);
    }

    /// <inheritdoc />
    public async Task<StorageFile?> GetByObjectKeyAsync(string objectKey, CancellationToken cancellationToken = default)
    {
        return await _context.StorageFiles
            .FirstOrDefaultAsync(f => f.ObjectKey == objectKey, cancellationToken);
    }

    /// <inheritdoc />
    public async Task<IEnumerable<StorageFile>> GetByUserIdAsync(
        string userId,
        int skip = 0,
        int take = 20,
        CancellationToken cancellationToken = default)
    {
        return await _context.StorageFiles
            .Where(f => f.UserId == userId)
            .OrderByDescending(f => f.UploadedAt)
            .Skip(skip)
            .Take(take)
            .ToListAsync(cancellationToken);
    }

    /// <inheritdoc />
    public async Task<long> GetTotalSizeByUserIdAsync(string userId, CancellationToken cancellationToken = default)
    {
        return await _context.StorageFiles
            .Where(f => f.UserId == userId)
            .SumAsync(f => f.FileSizeBytes, cancellationToken);
    }

    /// <inheritdoc />
    public async Task<int> GetFileCountByUserIdAsync(string userId, CancellationToken cancellationToken = default)
    {
        return await _context.StorageFiles
            .Where(f => f.UserId == userId)
            .CountAsync(cancellationToken);
    }

    /// <inheritdoc />
    public async Task<IEnumerable<StorageFile>> SearchAsync(
        string userId,
        string? searchTerm,
        int skip = 0,
        int take = 20,
        CancellationToken cancellationToken = default)
    {
        var query = _context.StorageFiles.Where(f => f.UserId == userId);

        if (!string.IsNullOrWhiteSpace(searchTerm))
        {
            query = query.Where(f => EF.Functions.ILike(f.FileName, $"%{searchTerm}%"));
        }

        return await query
            .OrderByDescending(f => f.UploadedAt)
            .Skip(skip)
            .Take(take)
            .ToListAsync(cancellationToken);
    }
}
