import { PlayerActiveChangedEvent } from './events/player-active-changed.event';
import { PlayerRoleChangedEvent } from './events/player-role-changed.event';
import { PlayerCreatedEvent } from './events/player-created.event';
import { PublicAccessEnabledEvent, PublicAccessRotatedEvent } from './events/public-access-changed.event';
import { InviteLinkCreatedEvent } from './events/invite-link-created.event';
import { NotificationsListener } from './notifications.listener';

describe('NotificationsListener', () => {
  const notifications = { create: jest.fn() };
  const logger = { error: jest.fn() };
  let listener: NotificationsListener;

  beforeEach(() => {
    jest.resetAllMocks();
    listener = new NotificationsListener(notifications as any, logger as any);
  });

  it('creates a player_active_update notification', async () => {
    await listener.onPlayerActiveChanged(new PlayerActiveChangedEvent(10, 5, 1, 'Ada Lovelace', false));

    expect(notifications.create).toHaveBeenCalledWith({
      teamId: 10,
      event: 'player_active_update',
      actorUserId: 5,
      payload: { playerId: 1, playerName: 'Ada Lovelace', active: false },
    });
  });

  it('creates a player_team_role_update notification', async () => {
    await listener.onPlayerRoleChanged(new PlayerRoleChangedEvent(10, 5, 1, 'Ada Lovelace', 3));

    expect(notifications.create).toHaveBeenCalledWith({
      teamId: 10,
      event: 'player_team_role_update',
      actorUserId: 5,
      payload: { playerId: 1, playerName: 'Ada Lovelace', teamRoleId: 3 },
    });
  });

  it('creates a player_creation notification', async () => {
    await listener.onPlayerCreated(new PlayerCreatedEvent(10, 5, 1, 'Ada Lovelace'));

    expect(notifications.create).toHaveBeenCalledWith({
      teamId: 10,
      event: 'player_creation',
      actorUserId: 5,
      payload: { playerId: 1, playerName: 'Ada Lovelace' },
    });
  });

  it('creates a public_access_enabled notification', async () => {
    await listener.onPublicAccessEnabled(new PublicAccessEnabledEvent(10, 5));

    expect(notifications.create).toHaveBeenCalledWith({
      teamId: 10,
      event: 'public_access_enabled',
      actorUserId: 5,
      payload: {},
    });
  });

  it('creates a public_access_rotated notification', async () => {
    await listener.onPublicAccessRotated(new PublicAccessRotatedEvent(10, 5));

    expect(notifications.create).toHaveBeenCalledWith({
      teamId: 10,
      event: 'public_access_rotated',
      actorUserId: 5,
      payload: {},
    });
  });

  it('creates a user_invite_link_create notification', async () => {
    await listener.onInviteLinkCreated(new InviteLinkCreatedEvent(10, 5, 'Team A'));

    expect(notifications.create).toHaveBeenCalledWith({
      teamId: 10,
      event: 'user_invite_link_create',
      actorUserId: 5,
      payload: { teamName: 'Team A' },
    });
  });

  it('logs and swallows errors instead of throwing, so the originating action is unaffected', async () => {
    notifications.create.mockRejectedValue(new Error('db unavailable'));

    await expect(
      listener.onPlayerCreated(new PlayerCreatedEvent(10, 5, 1, 'Ada Lovelace')),
    ).resolves.toBeUndefined();

    expect(logger.error).toHaveBeenCalledWith({
      event: 'notification_create_fail',
      details: 'teamId=10 event=player_creation: db unavailable',
      userId: -1,
    });
  });
});
