#nullable enable
using Baya.Application.Common;
using Baya.Application.Contracts.Common;
using Baya.Application.Contracts.Persistence;
using Baya.Application.Models.Common;
using Baya.Application.Models.Identity;
using Baya.Domain.Entities.Identity;
using Baya.Domain.Entities.User;
using Mediator;

namespace Baya.Application.Features.Identity.Commands.UploadCustomerAvatar;

internal sealed class UploadCustomerAvatarCommandHandler(
    ICurrentUser currentUser,
    IUnitOfWork unitOfWork,
    IObjectStorage objectStorage)
    : IRequestHandler<UploadCustomerAvatarCommand, OperationResult<AvatarUploadResult>>
{
    public async ValueTask<OperationResult<AvatarUploadResult>> Handle(UploadCustomerAvatarCommand request, CancellationToken cancellationToken)
    {
        if (currentUser.UserId is not { } userId)
            return OperationResult<AvatarUploadResult>.UnauthorizedResult("Not authenticated.");

        if (currentUser.Roles?.Contains(RoleNames.Customer) != true)
            return OperationResult<AvatarUploadResult>.ForbiddenResult("Only a customer can upload a customer avatar.");

        if (!AvatarUpload.IsAllowedContentType(request.ContentType))
            return OperationResult<AvatarUploadResult>.FailureResult("Unsupported image type. Use JPEG, PNG, or WebP.");

        if (!AvatarUpload.IsWithinSizeLimit(request.Length))
            return OperationResult<AvatarUploadResult>.FailureResult("Image is empty or exceeds the 5 MB limit.");

        var profile = await unitOfWork.CustomerProfileRepository.GetByUserIdAsync(userId, cancellationToken);
        if (profile is null)
        {
            // Mirror the customer-profile upsert: provision the thin payer row so an avatar-first customer
            // still gets a profile to attach the URL to.
            profile = new CustomerProfile { UserId = userId };
            await unitOfWork.CustomerProfileRepository.AddAsync(profile, cancellationToken);
            await unitOfWork.CommitAsync();
        }

        var key = AvatarUpload.BuildKey("customer", profile.Id, request.ContentType, Guid.NewGuid().ToString("N"));
        using (var stream = new MemoryStream(request.Content))
            await objectStorage.PutAsync(key, stream, request.ContentType, cancellationToken);

        var url = objectStorage.GetUrl(key);
        profile.AvatarUrl = url;
        await unitOfWork.CommitAsync();

        return OperationResult<AvatarUploadResult>.SuccessResult(new AvatarUploadResult(url));
    }
}
