import { PrismaConversationRepository } from '../repositories/prisma-conversation.repository';

describe('PrismaConversationRepository', () => {
  let repository: PrismaConversationRepository;
  let mockPrisma: {
    conversation: {
      create: ReturnType<typeof vi.fn>;
      findUnique: ReturnType<typeof vi.fn>;
      findMany: ReturnType<typeof vi.fn>;
      findFirst: ReturnType<typeof vi.fn>;
      update: ReturnType<typeof vi.fn>;
      count: ReturnType<typeof vi.fn>;
    };
    conversationParticipant: {
      updateMany: ReturnType<typeof vi.fn>;
    };
  };

  const mockConversation = {
    id: 'conv-1',
    listingId: 'listing-1',
    subject: null,
    status: 'ACTIVE',
    lastMessage: null,
    lastMessageAt: null,
    createdAt: new Date(),
    updatedAt: new Date(),
    participants: [
      { id: 'p-1', conversationId: 'conv-1', userId: 'user-1', unreadCount: 0, lastReadAt: null, joinedAt: new Date() },
      { id: 'p-2', conversationId: 'conv-1', userId: 'user-2', unreadCount: 0, lastReadAt: null, joinedAt: new Date() },
    ],
  };

  beforeEach(() => {
    mockPrisma = {
      conversation: {
        create: vi.fn().mockResolvedValue(mockConversation),
        findUnique: vi.fn().mockResolvedValue(mockConversation),
        findMany: vi.fn().mockResolvedValue([mockConversation]),
        findFirst: vi.fn().mockResolvedValue(null),
        update: vi.fn().mockResolvedValue(mockConversation),
        count: vi.fn().mockResolvedValue(1),
      },
      conversationParticipant: {
        updateMany: vi.fn().mockResolvedValue({ count: 1 }),
      },
    };
    repository = new PrismaConversationRepository(mockPrisma as any);
  });

  it('creates a conversation with participants', async () => {
    const result = await repository.create({
      listingId: 'listing-1',
      participantUserIds: ['user-1', 'user-2'],
    });

    expect(mockPrisma.conversation.create).toHaveBeenCalledWith({
      data: {
        listingId: 'listing-1',
        subject: null,
        participants: {
          create: [{ userId: 'user-1' }, { userId: 'user-2' }],
        },
      },
      include: { participants: true },
    });
    expect(result.id).toBe('conv-1');
    expect(result.participants).toHaveLength(2);
  });

  it('finds conversation by id', async () => {
    const result = await repository.findById('conv-1');

    expect(mockPrisma.conversation.findUnique).toHaveBeenCalledWith({
      where: { id: 'conv-1' },
      include: { participants: true },
    });
    expect(result?.id).toBe('conv-1');
  });

  it('returns null when conversation not found', async () => {
    mockPrisma.conversation.findUnique.mockResolvedValue(null);

    const result = await repository.findById('conv-999');

    expect(result).toBeNull();
  });

  it('finds conversations by user id', async () => {
    const result = await repository.findByUserId('user-1', 20, 0);

    expect(mockPrisma.conversation.findMany).toHaveBeenCalledWith(
      expect.objectContaining({
        where: { participants: { some: { userId: 'user-1' } } },
        take: 20,
        skip: 0,
      }),
    );
    expect(result).toHaveLength(1);
  });

  it('updates conversation status', async () => {
    await repository.updateStatus('conv-1', 'CLOSED');

    expect(mockPrisma.conversation.update).toHaveBeenCalledWith({
      where: { id: 'conv-1' },
      data: { status: 'CLOSED' },
    });
  });

  it('increments unread count for other participants', async () => {
    await repository.incrementUnreadCount('conv-1', 'user-1');

    expect(mockPrisma.conversationParticipant.updateMany).toHaveBeenCalledWith({
      where: { conversationId: 'conv-1', userId: { not: 'user-1' } },
      data: { unreadCount: { increment: 1 } },
    });
  });

  it('resets unread count for a user', async () => {
    await repository.resetUnreadCount('conv-1', 'user-1');

    expect(mockPrisma.conversationParticipant.updateMany).toHaveBeenCalledWith({
      where: { conversationId: 'conv-1', userId: 'user-1' },
      data: { unreadCount: 0, lastReadAt: expect.any(Date) },
    });
  });

  it('counts conversations by user id', async () => {
    const count = await repository.countByUserId('user-1');

    expect(count).toBe(1);
  });
});
