using MediatR;
using SocialService.Domain.AggregatesModel.RelationshipAggregate;
using SocialService.Domain.AggregatesModel.UserBlockAggregate;
using SocialService.Domain.Exceptions;

namespace SocialService.API.Application.Commands;

/// <summary>
/// EN: Handler for BlockUserCommand.
/// VI: Handler cho BlockUserCommand.
/// </summary>
public class BlockUserCommandHandler : IRequestHandler<BlockUserCommand, BlockUserResult>
{
    private readonly IUserBlockRepository _userBlockRepository;
    private readonly IRelationshipRepository _relationshipRepository;
    private readonly ILogger<BlockUserCommandHandler> _logger;

    public BlockUserCommandHandler(
        IUserBlockRepository userBlockRepository,
        IRelationshipRepository relationshipRepository,
        ILogger<BlockUserCommandHandler> logger)
    {
        _userBlockRepository = userBlockRepository;
        _relationshipRepository = relationshipRepository;
        _logger = logger;
    }

    public async Task<BlockUserResult> Handle(BlockUserCommand request, CancellationToken cancellationToken)
    {
        // EN: Cannot block yourself
        // VI: Không thể block chính mình
        if (request.BlockerId == request.BlockedId)
        {
            throw new SocialDomainException("Cannot block yourself");
        }

        // EN: Check if already blocked
        // VI: Kiểm tra xem đã block chưa
        var existingBlock = await _userBlockRepository.GetByUsersAsync(request.BlockerId, request.BlockedId);
        if (existingBlock != null)
        {
            throw new SocialDomainException("User is already blocked");
        }

        // EN: Create block
        // VI: Tạo block
        var block = new UserBlock(request.BlockerId, request.BlockedId, request.Reason);
        _userBlockRepository.Add(block);

        // EN: Remove any existing relationships between the users
        // VI: Xóa các quan hệ đang tồn tại giữa hai users
        await RemoveExistingRelationshipsAsync(request.BlockerId, request.BlockedId);

        await _userBlockRepository.UnitOfWork.SaveEntitiesAsync(cancellationToken);

        _logger.LogInformation("User {BlockerId} blocked {BlockedId}",
            request.BlockerId, request.BlockedId);

        return new BlockUserResult(block.Id, true);
    }

    private async Task RemoveExistingRelationshipsAsync(Guid userId1, Guid userId2)
    {
        // EN: Remove friendship in both directions
        // VI: Xóa kết bạn theo cả hai hướng
        var friendship1 = await _relationshipRepository.GetByUsersAndTypeAsync(
            userId1, userId2, RelationshipType.Friendship);
        if (friendship1 != null)
        {
            friendship1.Remove();
            _relationshipRepository.Update(friendship1);
        }

        var friendship2 = await _relationshipRepository.GetByUsersAndTypeAsync(
            userId2, userId1, RelationshipType.Friendship);
        if (friendship2 != null)
        {
            friendship2.Remove();
            _relationshipRepository.Update(friendship2);
        }

        // EN: Remove following in both directions
        // VI: Xóa following theo cả hai hướng
        var follow1 = await _relationshipRepository.GetByUsersAndTypeAsync(
            userId1, userId2, RelationshipType.Following);
        if (follow1 != null)
        {
            follow1.Remove();
            _relationshipRepository.Update(follow1);
        }

        var follow2 = await _relationshipRepository.GetByUsersAndTypeAsync(
            userId2, userId1, RelationshipType.Following);
        if (follow2 != null)
        {
            follow2.Remove();
            _relationshipRepository.Update(follow2);
        }
    }
}
