import { FollowsService } from './follows.service';

describe('FollowsService', () => {
  it('keeps follow successful even if notification creation fails and resyncs counters', async () => {
    const currentUserId = '507f1f77bcf86cd799439011';
    const targetUserId = '507f191e810c19729de860ea';

    const followsRepository = {
      findOne: jest.fn().mockResolvedValue(null),
      create: jest.fn().mockResolvedValue({ id: 'follow-1' }),
      count: jest
        .fn()
        .mockResolvedValueOnce(6)
        .mockResolvedValueOnce(14),
    };
    const usersRepository = {
      findById: jest.fn().mockResolvedValue({ id: targetUserId }),
      setFollowingCount: jest.fn().mockResolvedValue(undefined),
      setFollowersCount: jest.fn().mockResolvedValue(undefined),
    };
    const outboxService = {
      enqueueFollowNotification: jest.fn().mockRejectedValue(new Error('socket down')),
    };
    const blocksRepository = {
      findAnyBetween: jest.fn().mockResolvedValue(null),
    };

    const service = new FollowsService(
      followsRepository as any,
      usersRepository as any,
      outboxService as any,
      { bumpGlobalVersion: jest.fn().mockResolvedValue(1) } as any,
      blocksRepository as any,
    );

    await expect(service.toggleFollow(currentUserId, { targetUserId })).resolves.toEqual({
      following: true,
    });
    expect(usersRepository.setFollowingCount).toHaveBeenCalledWith(currentUserId, 6);
    expect(usersRepository.setFollowersCount).toHaveBeenCalledWith(targetUserId, 14);
    expect(outboxService.enqueueFollowNotification).toHaveBeenCalledWith(
      currentUserId,
      targetUserId,
      'follow-1',
    );
  });

  it('prevents users from following themselves', async () => {
    const userId = '507f1f77bcf86cd799439011';
    const service = new FollowsService(
      {} as any,
      {} as any,
      {} as any,
      { bumpGlobalVersion: jest.fn() } as any,
      { findAnyBetween: jest.fn() } as any,
    );

    await expect(service.followUser(userId, userId)).rejects.toThrow('You cannot follow yourself');
  });

  it('returns already-following response without creating duplicate notification', async () => {
    const currentUserId = '507f1f77bcf86cd799439011';
    const targetUserId = '507f191e810c19729de860ea';
    const followsRepository = {
      findOne: jest.fn().mockResolvedValue({ id: 'existing-follow' }),
      count: jest.fn().mockResolvedValueOnce(1).mockResolvedValueOnce(2),
      create: jest.fn(),
    };
    const usersRepository = {
      findById: jest.fn().mockResolvedValue({ id: targetUserId, isDisabled: false, isPrivate: false }),
      setFollowingCount: jest.fn(),
      setFollowersCount: jest.fn(),
    };
    const outboxService = {
      enqueueFollowNotification: jest.fn(),
    };
    const service = new FollowsService(
      followsRepository as any,
      usersRepository as any,
      outboxService as any,
      { bumpGlobalVersion: jest.fn() } as any,
      { findAnyBetween: jest.fn().mockResolvedValue(null) } as any,
    );

    await expect(service.followUser(currentUserId, targetUserId)).resolves.toMatchObject({
      message: 'Already following user',
      isFollowing: true,
      followersCount: 2,
      followingCount: 1,
    });
    expect(followsRepository.create).not.toHaveBeenCalled();
    expect(outboxService.enqueueFollowNotification).not.toHaveBeenCalled();
  });
});
