import { CreateSavedSearchCommand } from '../commands/create-saved-search/create-saved-search.command';
import { CreateSavedSearchHandler } from '../commands/create-saved-search/create-saved-search.handler';

describe('CreateSavedSearchHandler', () => {
  let handler: CreateSavedSearchHandler;
  let mockPrisma: any;
  let mockEventBus: { publish: ReturnType<typeof vi.fn> };
  let mockLogger: { log: ReturnType<typeof vi.fn>; warn: ReturnType<typeof vi.fn>; error: ReturnType<typeof vi.fn> };

  beforeEach(() => {
    mockPrisma = {
      savedSearch: {
        create: vi.fn(),
        findMany: vi.fn(),
        count: vi.fn(),
      },
    };
    mockEventBus = { publish: vi.fn() };
    mockLogger = { log: vi.fn(), warn: vi.fn(), error: vi.fn() };

    handler = new CreateSavedSearchHandler(
      mockPrisma,
      mockEventBus as any,
      mockLogger as any,
    );
  });

  it('creates a saved search successfully and publishes domain event', async () => {
    const now = new Date();
    mockPrisma.savedSearch.create.mockResolvedValue({
      id: 'saved-1',
      userId: 'user-1',
      name: 'Chung cư Q7',
      filters: { district: 'Quan 7', propertyType: 'APARTMENT' },
      alertEnabled: true,
      lastAlertAt: null,
      createdAt: now,
    });

    const command = new CreateSavedSearchCommand(
      'user-1',
      'Chung cư Q7',
      { district: 'Quan 7', propertyType: 'APARTMENT' },
      true,
    );
    const result = await handler.execute(command);

    expect(result.name).toBe('Chung cư Q7');
    expect(result.alertEnabled).toBe(true);
    expect(mockPrisma.savedSearch.create).toHaveBeenCalledTimes(1);
    expect(mockEventBus.publish).toHaveBeenCalledTimes(1);
    expect(mockEventBus.publish.mock.calls[0]?.[0]?.eventName).toBe('saved-search.created');
    expect(mockEventBus.publish.mock.calls[0]?.[0]?.userId).toBe('user-1');
  });

  it('throws when name is empty', async () => {
    const command = new CreateSavedSearchCommand('user-1', '', {}, true);
    await expect(handler.execute(command)).rejects.toThrow('Tên tìm kiếm không được để trống');
  });

  it('throws when name exceeds 100 characters', async () => {
    const longName = 'a'.repeat(101);
    const command = new CreateSavedSearchCommand('user-1', longName, {}, true);
    await expect(handler.execute(command)).rejects.toThrow('Tên tìm kiếm không được vượt quá 100 ký tự');
  });
});
