import { PlayerMessagesService } from './player-messages.service';

describe('PlayerMessagesService', () => {
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  const prisma: any = {
    playerMessage: {
      create: jest.fn(),
      findMany: jest.fn(),
      count: jest.fn(),
      findFirst: jest.fn(),
      update: jest.fn(),
      updateMany: jest.fn(),
      delete: jest.fn(),
      deleteMany: jest.fn(),
      createMany: jest.fn(),
    },
    playerMessageBroadcast: {
      findMany: jest.fn(),
      count: jest.fn(),
      findUnique: jest.fn(),
      create: jest.fn(),
      delete: jest.fn(),
    },
    user: {
      findUnique: jest.fn(),
      findMany: jest.fn(),
      findFirst: jest.fn(),
    },
    $transaction: jest.fn(async (fn: (tx: typeof prisma) => Promise<unknown>) => fn(prisma)),
  };

  let service: PlayerMessagesService;

  beforeEach(() => {
    jest.clearAllMocks();
    service = new PlayerMessagesService(prisma as never);
  });

  it('creates localized deposit approved messages', async () => {
    prisma.playerMessage.create.mockResolvedValue({
      id: 1n,
      type: 'DEPOSIT_APPROVED',
      title: '充值已到账',
      body: 'body',
      payload: { orderNo: 'DEP-1' },
      readAt: null,
      createdAt: new Date('2026-06-17T10:00:00.000Z'),
    });

    const result = await service.createDepositApprovedMessage(7n, {
      depositOrderId: 10n,
      orderNo: 'DEP-1',
      amount: '100',
      approvedAmount: '100',
      locale: 'zh-CN',
    });

    expect(prisma.playerMessage.create).toHaveBeenCalledWith(
      expect.objectContaining({
        data: expect.objectContaining({
          userId: 7n,
          type: 'DEPOSIT_APPROVED',
          title: '充值已到账',
        }),
      }),
    );
    expect(result.type).toBe('DEPOSIT_APPROVED');
    expect(result.isRead).toBe(false);
  });

  it('returns paginated inbox with unread count', async () => {
    prisma.playerMessage.findMany.mockResolvedValue([
      {
        id: 2n,
        type: 'DEPOSIT_REJECTED',
        title: 'Deposit rejected',
        body: 'Rejected',
        payload: null,
        readAt: null,
        createdAt: new Date('2026-06-17T11:00:00.000Z'),
      },
    ]);
    prisma.playerMessage.count.mockResolvedValueOnce(1).mockResolvedValueOnce(1);

    const result = await service.listForPlayer(7n, 1, 20);

    expect(result.items).toHaveLength(1);
    expect(result.unreadCount).toBe(1);
    expect(result.total).toBe(1);
  });

  it('deletes a single message for the player', async () => {
    prisma.playerMessage.findFirst.mockResolvedValue({
      id: 3n,
      type: 'DEPOSIT_APPROVED',
      title: 'Deposit approved',
      body: 'body',
      payload: null,
      readAt: null,
      createdAt: new Date('2026-06-17T12:00:00.000Z'),
    });
    prisma.playerMessage.delete.mockResolvedValue({ id: 3n });

    const result = await service.deleteForPlayer(7n, 3n);

    expect(prisma.playerMessage.delete).toHaveBeenCalledWith({ where: { id: 3n } });
    expect(result).toEqual({ deleted: true, wasUnread: true });
  });

  it('deletes all messages for the player', async () => {
    prisma.playerMessage.deleteMany.mockResolvedValue({ count: 4 });

    const result = await service.deleteAllForPlayer(7n);

    expect(prisma.playerMessage.deleteMany).toHaveBeenCalledWith({ where: { userId: 7n } });
    expect(result).toEqual({ deleted: 4 });
  });

  it('broadcasts banner promotion inbox messages to active players', async () => {
    prisma.user.findMany.mockResolvedValue([
      { id: 10n, locale: 'zh-CN', preferences: { locale: 'zh-CN' } },
      { id: 11n, locale: 'en-US', preferences: null },
    ]);
    prisma.playerMessage.createMany.mockResolvedValue({ count: 2 });

    const count = await service.broadcastBannerPromotion({
      contentId: 99n,
      translations: [
        { locale: 'zh-CN', title: '夏季活动', body: '<p>限时优惠</p>' },
        { locale: 'en-US', title: 'Summer promo', body: '' },
      ],
    });

    expect(count).toBe(2);
    expect(prisma.playerMessage.createMany).toHaveBeenCalledWith({
      data: expect.arrayContaining([
        expect.objectContaining({
          userId: 10n,
          type: 'BANNER_PROMO',
          title: '夏季活动',
          body: '限时优惠',
        }),
        expect.objectContaining({
          userId: 11n,
          type: 'BANNER_PROMO',
          title: 'Summer promo',
        }),
      ]),
    });
  });

  it('broadcasts announcement promotion inbox messages to active players', async () => {
    prisma.user.findMany.mockResolvedValue([
      { id: 10n, locale: 'zh-CN', preferences: { locale: 'zh-CN' } },
    ]);
    prisma.playerMessage.createMany.mockResolvedValue({ count: 1 });

    const count = await service.broadcastAnnouncementPromotion({
      contentId: 100n,
      translations: [{ locale: 'zh-CN', title: '维护通知', body: '系统维护中' }],
    });

    expect(count).toBe(1);
    expect(prisma.playerMessage.createMany).toHaveBeenCalledWith({
      data: [
        expect.objectContaining({
          userId: 10n,
          type: 'ANNOUNCEMENT_PROMO',
          title: '维护通知',
          body: '系统维护中',
        }),
      ],
    });
  });

  it('creates custom broadcast to all active players', async () => {
    prisma.user.findMany.mockResolvedValue([
      { id: 1n, username: 'p1', locale: 'zh-CN', preferences: { locale: 'zh-CN' } },
      { id: 2n, username: 'p2', locale: 'en-US', preferences: null },
    ]);
    prisma.playerMessageBroadcast.create.mockResolvedValue({
      id: 9n,
      title: 'Hello',
      body: '<p>World</p>',
      translations: {
        'en-US': { title: 'Hello', body: '<p>World</p>' },
        'zh-CN': { title: '你好', body: '<p>内容</p>' },
      },
      targetType: 'ALL',
      targetUserId: null,
      targetUsername: null,
      recipientCount: 2,
      createdById: 99n,
      createdByUsername: 'admin',
      createdAt: new Date('2026-06-22T10:00:00.000Z'),
    });

    const result = await service.createCustomBroadcast({
      translations: [
        { locale: 'en-US', title: 'Hello', body: '<p>World</p>' },
        { locale: 'zh-CN', title: '你好', body: '<p>内容</p>' },
      ],
      targetType: 'ALL',
      createdById: 99n,
      createdByUsername: 'admin',
    });

    expect(result.recipientCount).toBe(2);
    expect(prisma.playerMessage.createMany).toHaveBeenCalledWith({
      data: [
        expect.objectContaining({ userId: 1n, type: 'ADMIN_CUSTOM', title: '你好', broadcastId: 9n }),
        expect.objectContaining({ userId: 2n, type: 'ADMIN_CUSTOM', title: 'Hello', broadcastId: 9n }),
      ],
    });
  });

  it('deletes broadcast and cascades player messages', async () => {
    prisma.playerMessageBroadcast.findUnique.mockResolvedValue({
      id: 5n,
      recipientCount: 3,
    });
    prisma.playerMessageBroadcast.delete.mockResolvedValue({ id: 5n });

    const result = await service.deleteBroadcast(5n);

    expect(result).toEqual({ deleted: true, recipientCount: 3 });
    expect(prisma.playerMessageBroadcast.delete).toHaveBeenCalledWith({ where: { id: 5n } });
  });
});
