import { type CacheService } from '@modules/shared/infrastructure/cache.service';
import { MarketIndexEntity } from '../../domain/entities/market-index.entity';
import { type IMarketIndexRepository } from '../../domain/repositories/market-index.repository';
import { UpdateMarketIndexCommand } from '../commands/update-market-index/update-market-index.command';
import { UpdateMarketIndexHandler } from '../commands/update-market-index/update-market-index.handler';

function createExistingEntity(): MarketIndexEntity {
  return new MarketIndexEntity('idx-1', {
    district: 'Quận 1',
    city: 'Hồ Chí Minh',
    propertyType: 'APARTMENT',
    period: '2026-Q1',
    medianPrice: BigInt(4000000000),
    avgPriceM2: 70000000,
    totalListings: 100,
    daysOnMarket: 40,
    inventoryLevel: 3.0,
    absorptionRate: 0.6,
    yoyChange: 0.05,
  });
}

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

  beforeEach(() => {
    mockRepo = {
      findById: vi.fn(),
      findByKey: vi.fn(),
      save: vi.fn(),
      update: vi.fn(),
      getMarketReport: vi.fn(),
      getHeatmap: vi.fn(),
      getPriceTrend: vi.fn(),
      getDistrictStats: vi.fn(),
    };
    const mockCache = { invalidateByPrefix: vi.fn() } as unknown as CacheService;
    handler = new UpdateMarketIndexHandler(mockRepo as any, mockCache);
  });

  it('creates a new market index when none exists', async () => {
    mockRepo.findByKey.mockResolvedValue(null);
    mockRepo.save.mockResolvedValue(undefined);

    const command = new UpdateMarketIndexCommand(
      'Quận 7', 'Hồ Chí Minh', 'APARTMENT', '2026-Q1',
      BigInt(5000000000), 80000000, 150, 45, 3.2, 0.65, 0.08,
    );

    const result = await handler.execute(command);

    expect(result.created).toBe(true);
    expect(result.id).toBeDefined();
    expect(mockRepo.save).toHaveBeenCalledTimes(1);
    expect(mockRepo.update).not.toHaveBeenCalled();
  });

  it('updates an existing market index', async () => {
    const existing = createExistingEntity();
    mockRepo.findByKey.mockResolvedValue(existing);
    mockRepo.update.mockResolvedValue(undefined);

    const command = new UpdateMarketIndexCommand(
      'Quận 1', 'Hồ Chí Minh', 'APARTMENT', '2026-Q1',
      BigInt(5500000000), 85000000, 160, 42, 3.5, 0.7, 0.1,
    );

    const result = await handler.execute(command);

    expect(result.created).toBe(false);
    expect(result.id).toBe('idx-1');
    expect(mockRepo.update).toHaveBeenCalledTimes(1);
    expect(mockRepo.save).not.toHaveBeenCalled();
  });

  it('passes correct key parameters to findByKey', async () => {
    mockRepo.findByKey.mockResolvedValue(null);
    mockRepo.save.mockResolvedValue(undefined);

    const command = new UpdateMarketIndexCommand(
      'Quận 3', 'Hồ Chí Minh', 'HOUSE', '2026-Q2',
      BigInt(3000000000), 60000000, 80, 50, 2.5,
    );

    await handler.execute(command);

    expect(mockRepo.findByKey).toHaveBeenCalledWith('Quận 3', 'Hồ Chí Minh', 'HOUSE', '2026-Q2');
  });
});
