import { ConflictException } from '@modules/shared';
import type { IIndustrialParkRepository } from '../../domain/repositories/industrial-park.repository';
import type { TypesenseIndustrialService } from '../../infrastructure/services/typesense-industrial.service';
import { CreateIndustrialParkHandler } from '../commands/create-industrial-park/create-industrial-park.handler';
import { CreateIndustrialParkCommand } from '../commands/create-industrial-park/create-industrial-park.command';

describe('CreateIndustrialParkHandler', () => {
  let handler: CreateIndustrialParkHandler;
  let mockRepo: { [K in keyof IIndustrialParkRepository]: ReturnType<typeof vi.fn> };
  let mockTypesense: { [K in keyof TypesenseIndustrialService]: ReturnType<typeof vi.fn> };

  const baseCmd = new CreateIndustrialParkCommand(
    'KCN Bình Dương 3',
    'Binh Duong 3 IP',
    'kcn-binh-duong-3',
    'Becamex IDC',
    null,
    'OPERATIONAL',
    11.05,
    106.67,
    '123 Đại lộ Bình Dương',
    'Thủ Dầu Một',
    'Bình Dương',
    'SOUTH',
    500,
    400,
    72,
    112,
    45,
    2005,
    120,
    5.5,
    4.8,
    0.8,
    null,
    null,
    null,
    ['Electronics', 'Automotive'],
    'Khu công nghiệp Bình Dương 3',
    'Binh Duong 3 Industrial Park',
  );

  beforeEach(() => {
    mockRepo = {
      findById: vi.fn(),
      findBySlug: vi.fn(),
      findDetailBySlug: vi.fn(),
      findDetailById: vi.fn(),
      save: vi.fn(),
      update: vi.fn(),
      search: vi.fn(),
      compareParks: vi.fn(),
      getStats: vi.fn(),
      getMarketData: vi.fn(),
    };
    mockTypesense = {
      onModuleInit: vi.fn(),
      syncParks: vi.fn(),
      syncListings: vi.fn(),
      indexPark: vi.fn().mockResolvedValue(undefined),
      indexListing: vi.fn(),
      deleteListing: vi.fn(),
    } as any;
    handler = new CreateIndustrialParkHandler(mockRepo as any, mockTypesense as any);
  });

  it('creates a park and returns its id', async () => {
    mockRepo.findBySlug.mockResolvedValue(null);
    mockRepo.save.mockResolvedValue(undefined);

    const result = await handler.execute(baseCmd);

    expect(result).toHaveProperty('id');
    expect(typeof result.id).toBe('string');
    expect(mockRepo.findBySlug).toHaveBeenCalledWith('kcn-binh-duong-3');
    expect(mockRepo.save).toHaveBeenCalledTimes(1);
    expect(mockTypesense.indexPark).toHaveBeenCalledWith(result.id);
  });

  it('throws ConflictException when slug already exists', async () => {
    mockRepo.findBySlug.mockResolvedValue({ id: 'existing' });

    await expect(handler.execute(baseCmd)).rejects.toThrow(ConflictException);
    expect(mockRepo.save).not.toHaveBeenCalled();
  });

  it('sets isVerified to false on new parks', async () => {
    mockRepo.findBySlug.mockResolvedValue(null);
    mockRepo.save.mockResolvedValue(undefined);

    await handler.execute(baseCmd);

    const savedEntity = mockRepo.save.mock.calls[0]![0];
    expect(savedEntity.isVerified).toBe(false);
  });

  it('does not fail if Typesense indexing rejects', async () => {
    mockRepo.findBySlug.mockResolvedValue(null);
    mockRepo.save.mockResolvedValue(undefined);
    mockTypesense.indexPark.mockRejectedValue(new Error('Typesense down'));

    const result = await handler.execute(baseCmd);
    expect(result).toHaveProperty('id');
  });
});
