import { type PropertyType } from '@prisma/client';
import { AggregateRoot } from '@modules/shared';
import { MarketIndexUpdatedEvent } from '../events/market-index-updated.event';

export interface MarketIndexProps {
  district: string;
  city: string;
  propertyType: PropertyType;
  period: string;
  medianPrice: bigint;
  avgPriceM2: number;
  totalListings: number;
  daysOnMarket: number;
  inventoryLevel: number;
  absorptionRate: number | null;
  yoyChange: number | null;
}

export class MarketIndexEntity extends AggregateRoot<string> {
  private _district: string;
  private _city: string;
  private _propertyType: PropertyType;
  private _period: string;
  private _medianPrice: bigint;
  private _avgPriceM2: number;
  private _totalListings: number;
  private _daysOnMarket: number;
  private _inventoryLevel: number;
  private _absorptionRate: number | null;
  private _yoyChange: number | null;

  constructor(id: string, props: MarketIndexProps, createdAt?: Date, updatedAt?: Date) {
    super(id, createdAt, updatedAt);
    this._district = props.district;
    this._city = props.city;
    this._propertyType = props.propertyType;
    this._period = props.period;
    this._medianPrice = props.medianPrice;
    this._avgPriceM2 = props.avgPriceM2;
    this._totalListings = props.totalListings;
    this._daysOnMarket = props.daysOnMarket;
    this._inventoryLevel = props.inventoryLevel;
    this._absorptionRate = props.absorptionRate;
    this._yoyChange = props.yoyChange;
  }

  get district(): string { return this._district; }
  get city(): string { return this._city; }
  get propertyType(): PropertyType { return this._propertyType; }
  get period(): string { return this._period; }
  get medianPrice(): bigint { return this._medianPrice; }
  get avgPriceM2(): number { return this._avgPriceM2; }
  get totalListings(): number { return this._totalListings; }
  get daysOnMarket(): number { return this._daysOnMarket; }
  get inventoryLevel(): number { return this._inventoryLevel; }
  get absorptionRate(): number | null { return this._absorptionRate; }
  get yoyChange(): number | null { return this._yoyChange; }

  static createNew(
    id: string,
    district: string,
    city: string,
    propertyType: PropertyType,
    period: string,
    medianPrice: bigint,
    avgPriceM2: number,
    totalListings: number,
    daysOnMarket: number,
    inventoryLevel: number,
    absorptionRate?: number,
    yoyChange?: number,
  ): MarketIndexEntity {
    const entity = new MarketIndexEntity(id, {
      district,
      city,
      propertyType,
      period,
      medianPrice,
      avgPriceM2,
      totalListings,
      daysOnMarket,
      inventoryLevel,
      absorptionRate: absorptionRate ?? null,
      yoyChange: yoyChange ?? null,
    });

    entity.addDomainEvent(new MarketIndexUpdatedEvent(id, district, city, period));
    return entity;
  }

  updateMetrics(
    medianPrice: bigint,
    avgPriceM2: number,
    totalListings: number,
    daysOnMarket: number,
    inventoryLevel: number,
    absorptionRate?: number,
    yoyChange?: number,
  ): void {
    this._medianPrice = medianPrice;
    this._avgPriceM2 = avgPriceM2;
    this._totalListings = totalListings;
    this._daysOnMarket = daysOnMarket;
    this._inventoryLevel = inventoryLevel;
    this._absorptionRate = absorptionRate ?? this._absorptionRate;
    this._yoyChange = yoyChange ?? this._yoyChange;
    this.updatedAt = new Date();

    this.addDomainEvent(new MarketIndexUpdatedEvent(this.id, this._district, this._city, this._period));
  }
}
