import { MarketIndexEntity } from '../entities/market-index.entity';
import { MarketIndexUpdatedEvent } from '../events/market-index-updated.event';

describe('MarketIndexEntity', () => {
  it('createNew creates entity with all properties and adds MarketIndexUpdatedEvent', () => {
    const entity = MarketIndexEntity.createNew(
      'idx-1',
      'Quận 1',
      'Hồ Chí Minh',
      'APARTMENT',
      '2026-Q1',
      BigInt(5000000000),
      80000000,
      150,
      45,
      3,
      0.65,
      0.08,
    );

    expect(entity.id).toBe('idx-1');
    expect(entity.district).toBe('Quận 1');
    expect(entity.city).toBe('Hồ Chí Minh');
    expect(entity.propertyType).toBe('APARTMENT');
    expect(entity.period).toBe('2026-Q1');
    expect(entity.medianPrice).toBe(BigInt(5000000000));
    expect(entity.avgPriceM2).toBe(80000000);
    expect(entity.totalListings).toBe(150);
    expect(entity.daysOnMarket).toBe(45);
    expect(entity.inventoryLevel).toBe(3);
    expect(entity.absorptionRate).toBe(0.65);
    expect(entity.yoyChange).toBe(0.08);

    const events = entity.domainEvents;
    expect(events).toHaveLength(1);
    expect(events[0]).toBeInstanceOf(MarketIndexUpdatedEvent);
    const event = events[0] as MarketIndexUpdatedEvent;
    expect(event.aggregateId).toBe('idx-1');
    expect(event.district).toBe('Quận 1');
    expect(event.city).toBe('Hồ Chí Minh');
    expect(event.period).toBe('2026-Q1');
  });

  it('createNew handles optional absorptionRate and yoyChange (null when not provided)', () => {
    const entity = MarketIndexEntity.createNew(
      'idx-2',
      'Quận 2',
      'Hồ Chí Minh',
      'VILLA',
      '2026-Q1',
      BigInt(8000000000),
      120000000,
      50,
      60,
      2,
    );

    expect(entity.absorptionRate).toBeNull();
    expect(entity.yoyChange).toBeNull();
  });

  it('updateMetrics updates all metric fields and adds MarketIndexUpdatedEvent', () => {
    const entity = MarketIndexEntity.createNew(
      'idx-3',
      'Quận 3',
      'Hồ Chí Minh',
      'APARTMENT',
      '2026-Q1',
      BigInt(5000000000),
      80000000,
      150,
      45,
      3,
      0.65,
      0.08,
    );
    entity.clearDomainEvents();

    entity.updateMetrics(
      BigInt(6000000000),
      90000000,
      200,
      40,
      4,
      0.70,
      0.10,
    );

    expect(entity.medianPrice).toBe(BigInt(6000000000));
    expect(entity.avgPriceM2).toBe(90000000);
    expect(entity.totalListings).toBe(200);
    expect(entity.daysOnMarket).toBe(40);
    expect(entity.inventoryLevel).toBe(4);
    expect(entity.absorptionRate).toBe(0.70);
    expect(entity.yoyChange).toBe(0.10);

    const events = entity.domainEvents;
    expect(events).toHaveLength(1);
    expect(events[0]).toBeInstanceOf(MarketIndexUpdatedEvent);
  });

  it('updateMetrics preserves existing absorptionRate when not provided', () => {
    const entity = MarketIndexEntity.createNew(
      'idx-4',
      'Quận 4',
      'Hồ Chí Minh',
      'APARTMENT',
      '2026-Q1',
      BigInt(5000000000),
      80000000,
      150,
      45,
      3,
      0.65,
      0.08,
    );

    entity.updateMetrics(
      BigInt(5500000000),
      85000000,
      160,
      42,
      3,
    );

    expect(entity.absorptionRate).toBe(0.65);
    expect(entity.yoyChange).toBe(0.08);
  });

  it('constructor sets all properties from props', () => {
    const createdAt = new Date('2026-01-01');
    const updatedAt = new Date('2026-03-01');
    const entity = new MarketIndexEntity(
      'idx-5',
      {
        district: 'Bình Thạnh',
        city: 'Hồ Chí Minh',
        propertyType: 'TOWNHOUSE',
        period: '2026-Q1',
        medianPrice: BigInt(3000000000),
        avgPriceM2: 60000000,
        totalListings: 80,
        daysOnMarket: 30,
        inventoryLevel: 2,
        absorptionRate: 0.50,
        yoyChange: 0.05,
      },
      createdAt,
      updatedAt,
    );

    expect(entity.id).toBe('idx-5');
    expect(entity.district).toBe('Bình Thạnh');
    expect(entity.city).toBe('Hồ Chí Minh');
    expect(entity.propertyType).toBe('TOWNHOUSE');
    expect(entity.period).toBe('2026-Q1');
    expect(entity.medianPrice).toBe(BigInt(3000000000));
    expect(entity.avgPriceM2).toBe(60000000);
    expect(entity.totalListings).toBe(80);
    expect(entity.daysOnMarket).toBe(30);
    expect(entity.inventoryLevel).toBe(2);
    expect(entity.absorptionRate).toBe(0.50);
    expect(entity.yoyChange).toBe(0.05);
    expect(entity.createdAt).toBe(createdAt);
    expect(entity.domainEvents).toHaveLength(0);
  });
});
