using MediatR;
using StorageService.Domain.AggregatesModel.FileAggregate;
using StorageService.Domain.AggregatesModel.FileShareAggregate;
using StorageService.Infrastructure.Storage;

namespace StorageService.API.Application.Queries;

/// <summary>
/// EN: Handler for GetFileSharesQuery.
/// VI: Handler cho GetFileSharesQuery.
/// </summary>
public class GetFileSharesQueryHandler : IRequestHandler<GetFileSharesQuery, IEnumerable<FileShareDto>>
{
    private readonly IFileShareRepository _fileShareRepository;
    private readonly IFileRepository _fileRepository;
    private readonly ILogger<GetFileSharesQueryHandler> _logger;

    public GetFileSharesQueryHandler(
        IFileShareRepository fileShareRepository,
        IFileRepository fileRepository,
        ILogger<GetFileSharesQueryHandler> logger)
    {
        _fileShareRepository = fileShareRepository;
        _fileRepository = fileRepository;
        _logger = logger;
    }

    public async Task<IEnumerable<FileShareDto>> Handle(GetFileSharesQuery request, CancellationToken cancellationToken)
    {
        _logger.LogDebug("Getting shares for file {FileId} by user {UserId}", request.FileId, request.UserId);

        // EN: Verify user owns the file / VI: Kiểm tra user sở hữu file
        var file = await _fileRepository.GetByIdAsync(request.FileId, cancellationToken);
        if (file == null || file.UserId != request.UserId)
        {
            return Enumerable.Empty<FileShareDto>();
        }

        var shares = await _fileShareRepository.GetByFileIdAsync(request.FileId, cancellationToken);

        return shares.Select(s => new FileShareDto(
            Id: s.Id,
            FileId: s.FileId,
            SharedBy: s.SharedBy,
            SharedWith: s.SharedWith,
            Permission: s.Permission.ToString(),
            ShareToken: s.ShareToken,
            HasPassword: !string.IsNullOrEmpty(s.PasswordHash),
            ExpiresAt: s.ExpiresAt,
            MaxDownloads: s.MaxDownloads,
            DownloadCount: s.DownloadCount,
            Status: s.Status.ToString(),
            CreatedAt: s.CreatedAt));
    }
}

/// <summary>
/// EN: Handler for AccessSharedFileQuery - public access via share token.
/// VI: Handler cho AccessSharedFileQuery - truy cập công khai qua share token.
/// </summary>
public class AccessSharedFileQueryHandler : IRequestHandler<AccessSharedFileQuery, SharedFileAccessResult>
{
    private readonly IFileShareRepository _fileShareRepository;
    private readonly IFileRepository _fileRepository;
    private readonly IStorageProviderFactory _storageProviderFactory;
    private readonly ILogger<AccessSharedFileQueryHandler> _logger;

    public AccessSharedFileQueryHandler(
        IFileShareRepository fileShareRepository,
        IFileRepository fileRepository,
        IStorageProviderFactory storageProviderFactory,
        ILogger<AccessSharedFileQueryHandler> logger)
    {
        _fileShareRepository = fileShareRepository;
        _fileRepository = fileRepository;
        _storageProviderFactory = storageProviderFactory;
        _logger = logger;
    }

    public async Task<SharedFileAccessResult> Handle(AccessSharedFileQuery request, CancellationToken cancellationToken)
    {
        try
        {
            _logger.LogInformation("Accessing shared file with token: {Token}", request.Token[..Math.Min(8, request.Token.Length)] + "...");

            // EN: Get file share by token / VI: Lấy file share bằng token
            var fileShare = await _fileShareRepository.GetByTokenAsync(request.Token, cancellationToken);
            if (fileShare == null)
            {
                _logger.LogWarning("Share token not found: {Token}", request.Token[..Math.Min(8, request.Token.Length)] + "...");
                return SharedFileAccessResult.Fail("Share link not found or has expired.");
            }

            // EN: Validate share is still valid / VI: Kiểm tra share còn hợp lệ
            if (!fileShare.IsValid())
            {
                _logger.LogWarning("Share {ShareId} is no longer valid, status: {Status}", fileShare.Id, fileShare.Status);
                return SharedFileAccessResult.Fail($"Share link is {fileShare.Status.ToString().ToLower()}.");
            }

            // EN: Validate password if required / VI: Kiểm tra mật khẩu nếu cần
            if (!fileShare.ValidatePassword(request.Password))
            {
                return SharedFileAccessResult.Fail("Invalid password.");
            }

            // EN: Get the file / VI: Lấy file
            var file = await _fileRepository.GetByIdAsync(fileShare.FileId, cancellationToken);
            if (file == null)
            {
                return SharedFileAccessResult.Fail("File not found.");
            }

            // EN: Generate pre-signed download URL / VI: Tạo pre-signed URL để tải xuống
            var provider = _storageProviderFactory.GetProvider(file.Provider);
            var downloadUrl = await provider.GetPreSignedDownloadUrlAsync(
                file.BucketName,
                file.ObjectKey,
                3600, // EN: 1 hour expiration / VI: Hết hạn sau 1 giờ
                cancellationToken);

            // EN: Increment download count / VI: Tăng số lần tải xuống
            fileShare.IncrementDownloadCount();
            _fileShareRepository.Update(fileShare);
            await _fileShareRepository.UnitOfWork.SaveEntitiesAsync(cancellationToken);

            _logger.LogInformation(
                "Shared file accessed successfully: shareId={ShareId}, fileId={FileId}, downloadCount={Count}",
                fileShare.Id, file.Id, fileShare.DownloadCount);

            return SharedFileAccessResult.Ok(
                downloadUrl,
                file.FileName,
                file.ContentType,
                file.FileSizeBytes);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error accessing shared file with token");
            return SharedFileAccessResult.Fail("An error occurred while accessing the shared file.");
        }
    }
}
