import { InquiryCreatedEvent } from '@modules/inquiries/domain/events/inquiry-created.event';
import { CreateLeadCommand } from '../commands/create-lead/create-lead.command';
import { InquiryCreatedToLeadListener } from '../event-handlers/inquiry-created-to-lead.listener';

describe('InquiryCreatedToLeadListener', () => {
  let listener: InquiryCreatedToLeadListener;
  let mockCommandBus: { execute: ReturnType<typeof vi.fn> };
  let mockPrisma: {
    listing: { findUnique: ReturnType<typeof vi.fn> };
    user: { findUnique: ReturnType<typeof vi.fn> };
  };
  let mockLogger: {
    log: ReturnType<typeof vi.fn>;
    warn: ReturnType<typeof vi.fn>;
    debug: ReturnType<typeof vi.fn>;
    error: ReturnType<typeof vi.fn>;
  };

  const agentUserId = 'agent-user-1';
  const listingId = 'listing-1';
  const inquiryUserId = 'user-1';
  const inquiryId = 'inq-1';

  const mockListing = {
    id: listingId,
    agent: { user: { id: agentUserId } },
  };

  const mockSender = {
    fullName: 'Nguyen Van A',
    phone: '0901234567',
    email: 'a@test.com',
  };

  beforeEach(() => {
    mockCommandBus = { execute: vi.fn().mockResolvedValue({ id: 'lead-1', status: 'NEW', createdAt: new Date().toISOString() }) };
    mockPrisma = {
      listing: { findUnique: vi.fn().mockResolvedValue(mockListing) },
      user: { findUnique: vi.fn().mockResolvedValue(mockSender) },
    };
    mockLogger = { log: vi.fn(), warn: vi.fn(), debug: vi.fn(), error: vi.fn() };

    listener = new InquiryCreatedToLeadListener(
      mockCommandBus as any,
      mockPrisma as any,
      mockLogger as any,
    );
  });

  it('creates a lead when listing has an agent and sender is found', async () => {
    const event = new InquiryCreatedEvent(inquiryId, listingId, inquiryUserId);
    await listener.handle(event);

    expect(mockCommandBus.execute).toHaveBeenCalledOnce();
    const cmd = mockCommandBus.execute.mock.calls[0]![0] as CreateLeadCommand;
    expect(cmd).toBeInstanceOf(CreateLeadCommand);
    expect(cmd.agentUserId).toBe(agentUserId);
    expect(cmd.name).toBe(mockSender.fullName);
    expect(cmd.phone).toBe(mockSender.phone);
    expect(cmd.email).toBe(mockSender.email);
    expect(cmd.source).toBe('INQUIRY');
  });

  it('skips lead creation when listing has no agent', async () => {
    mockPrisma.listing.findUnique.mockResolvedValue({ id: listingId, agent: null });
    const event = new InquiryCreatedEvent(inquiryId, listingId, inquiryUserId);
    await listener.handle(event);

    expect(mockCommandBus.execute).not.toHaveBeenCalled();
    expect(mockLogger.debug).toHaveBeenCalled();
  });

  it('skips lead creation when listing is not found', async () => {
    mockPrisma.listing.findUnique.mockResolvedValue(null);
    const event = new InquiryCreatedEvent(inquiryId, listingId, inquiryUserId);
    await listener.handle(event);

    expect(mockCommandBus.execute).not.toHaveBeenCalled();
  });

  it('skips lead creation when sender user is not found', async () => {
    mockPrisma.user.findUnique.mockResolvedValue(null);
    const event = new InquiryCreatedEvent(inquiryId, listingId, inquiryUserId);
    await listener.handle(event);

    expect(mockCommandBus.execute).not.toHaveBeenCalled();
    expect(mockLogger.warn).toHaveBeenCalled();
  });

  it('does not throw when commandBus.execute rejects — failure is non-blocking', async () => {
    mockCommandBus.execute.mockRejectedValue(new Error('DB error'));
    const event = new InquiryCreatedEvent(inquiryId, listingId, inquiryUserId);
    await expect(listener.handle(event)).resolves.not.toThrow();
    expect(mockLogger.error).toHaveBeenCalled();
  });

  it('falls back to phone when sender has no fullName', async () => {
    mockPrisma.user.findUnique.mockResolvedValue({ fullName: null, phone: '0901234567', email: null });
    const event = new InquiryCreatedEvent(inquiryId, listingId, inquiryUserId);
    await listener.handle(event);

    const cmd = mockCommandBus.execute.mock.calls[0]![0] as CreateLeadCommand;
    expect(cmd.name).toBe('0901234567');
    expect(cmd.email).toBeNull();
  });
});
