using MediatR;
using StorageService.Domain.AggregatesModel.FileAggregate;
using StorageService.Domain.AggregatesModel.QuotaAggregate;
using StorageService.Infrastructure.Caching;
using StorageService.Infrastructure.Storage;

namespace StorageService.API.Application.Commands.Admin;

/// <summary>
/// EN: Handler for AdminDeleteFileCommand.
/// VI: Handler cho AdminDeleteFileCommand.
/// </summary>
public class AdminDeleteFileCommandHandler : IRequestHandler<AdminDeleteFileCommand, AdminDeleteFileResult>
{
    private readonly IFileRepository _fileRepository;
    private readonly IQuotaRepository _quotaRepository;
    private readonly IStorageProviderFactory _storageProviderFactory;
    private readonly IRedisCacheService _cache;
    private readonly ILogger<AdminDeleteFileCommandHandler> _logger;

    public AdminDeleteFileCommandHandler(
        IFileRepository fileRepository,
        IQuotaRepository quotaRepository,
        IStorageProviderFactory storageProviderFactory,
        IRedisCacheService cache,
        ILogger<AdminDeleteFileCommandHandler> logger)
    {
        _fileRepository = fileRepository;
        _quotaRepository = quotaRepository;
        _storageProviderFactory = storageProviderFactory;
        _cache = cache;
        _logger = logger;
    }

    public async Task<AdminDeleteFileResult> Handle(AdminDeleteFileCommand request, CancellationToken cancellationToken)
    {
        try
        {
            // EN: Get file metadata / VI: Lấy metadata file
            var file = await _fileRepository.GetByIdAsync(request.FileId, cancellationToken);
            
            if (file == null)
            {
                return new AdminDeleteFileResult(false, null, null, "File not found.");
            }

            var fileName = file.FileName;
            var fileOwner = file.UserId;
            var fileSize = file.FileSizeBytes;

            // EN: Log admin action / VI: Log hành động admin
            _logger.LogWarning(
                "Admin {AdminId} deleting file {FileId} (owner: {OwnerId}) for reason: {Reason}",
                request.AdminUserId, request.FileId, fileOwner, request.Reason);

            // EN: Delete from storage provider / VI: Xóa khỏi storage provider
            var provider = _storageProviderFactory.GetProvider(file.Provider);
            var deleted = await provider.DeleteAsync(file.BucketName, file.ObjectKey, cancellationToken);

            if (!deleted)
            {
                _logger.LogWarning("Failed to delete file from storage: {FileId}", request.FileId);
            }

            // EN: Soft delete file record / VI: Soft delete record file
            file.Delete();
            _fileRepository.Update(file);

            // EN: Update quota / VI: Cập nhật quota
            var quota = await _quotaRepository.GetByUserIdAsync(fileOwner, cancellationToken);
            if (quota != null)
            {
                quota.RemoveUsage(fileSize);
                _quotaRepository.Update(quota);
            }

            // EN: Save changes / VI: Lưu thay đổi
            await _fileRepository.UnitOfWork.SaveEntitiesAsync(cancellationToken);

            // EN: Invalidate caches / VI: Invalidate caches
            await _cache.DeleteAsync(CacheKeys.FileMetadata(request.FileId), cancellationToken);
            if (Guid.TryParse(fileOwner, out var ownerId))
            {
                await _cache.DeleteAsync(CacheKeys.UserQuota(ownerId), cancellationToken);
            }

            _logger.LogInformation(
                "File {FileId} deleted by admin {AdminId}. Reason: {Reason}",
                request.FileId, request.AdminUserId, request.Reason);

            return new AdminDeleteFileResult(true, fileName, fileOwner, null);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error deleting file {FileId} by admin", request.FileId);
            return new AdminDeleteFileResult(false, null, null, "An error occurred while deleting the file.");
        }
    }
}
