using MediatR;
using Modules.User.Application.Gateways;

namespace Modules.User.Application.Commands.Access;

public class UpdateRoleCommand : IRequest<int>
{
    public int RoleId { get; init; }
    public string? Name { get; init; } = null!;
    public string? Description { get; init; }
    public bool ChangeDescription { get; init; }
    public IReadOnlyCollection<int>? PermissionIds { get; init; }
}

public class RoleUpdateCommandHandler(IRoleRepository roleRepository, IPermissionRepository permissionRepository,
    IUnitOfWork uow) : IRequestHandler<UpdateRoleCommand, int>
{
    public async Task<int> Handle(UpdateRoleCommand request, CancellationToken cancellationToken)
    {
        var role = await roleRepository.GetAsync(request.RoleId, cancellationToken)
                   ?? throw new KeyNotFoundException("Role not found.");
        if (!string.IsNullOrWhiteSpace(request.Name))
        {
            var same = await roleRepository.GetByNameAsync(request.Name!, cancellationToken);
            if (same is not null && same.Id != request.RoleId)
                throw new InvalidOperationException("Role name must be unique.");
            role.SetName(request.Name);
        }
        
        if (request.ChangeDescription) role.SetDescription(request.Description);
        
        if (request.PermissionIds is not null)
        {
            if (request.PermissionIds.Count > 0 &&
                !await permissionRepository.ExistsAllAsync(request.PermissionIds, cancellationToken))
                throw new InvalidOperationException("Some permissions do not exist.");
            role.SyncPermissions(request.PermissionIds);
        }
        await roleRepository.AddAsync(role, cancellationToken);
        await uow.SaveChangesAsync(cancellationToken);
        return role.Id;
    }
}