import { Inject, InternalServerErrorException } from '@nestjs/common';
import { CommandHandler, type ICommandHandler } from '@nestjs/cqrs';
import { DomainException, CacheService, CachePrefix, LoggerService } from '@modules/shared';
import { MarketIndexEntity } from '../../../domain/entities/market-index.entity';
import {
  MARKET_INDEX_REPOSITORY,
  type IMarketIndexRepository,
} from '../../../domain/repositories/market-index.repository';
import { UpdateMarketIndexCommand } from './update-market-index.command';

export interface UpdateMarketIndexResult {
  id: string;
  created: boolean;
}

@CommandHandler(UpdateMarketIndexCommand)
export class UpdateMarketIndexHandler implements ICommandHandler<UpdateMarketIndexCommand> {
  constructor(
    @Inject(MARKET_INDEX_REPOSITORY) private readonly marketIndexRepo: IMarketIndexRepository,
    private readonly cache: CacheService,
    private readonly logger: LoggerService,
  ) {}

  async execute(command: UpdateMarketIndexCommand): Promise<UpdateMarketIndexResult> {
    try {
      const existing = await this.marketIndexRepo.findByKey(
        command.district,
        command.city,
        command.propertyType,
        command.period,
      );

      if (existing) {
        existing.updateMetrics(
          command.medianPrice,
          command.avgPriceM2,
          command.totalListings,
          command.daysOnMarket,
          command.inventoryLevel,
          command.absorptionRate,
          command.yoyChange,
        );
        await this.marketIndexRepo.update(existing);
        await this.invalidateMarketCaches();
        return { id: existing.id, created: false };
      }

      const id = crypto.randomUUID();
      const entity = MarketIndexEntity.createNew(
        id,
        command.district,
        command.city,
        command.propertyType,
        command.period,
        command.medianPrice,
        command.avgPriceM2,
        command.totalListings,
        command.daysOnMarket,
        command.inventoryLevel,
        command.absorptionRate,
        command.yoyChange,
      );

      await this.marketIndexRepo.save(entity);

      await this.invalidateMarketCaches();

      return { id, created: true };
    } catch (error) {
      if (error instanceof DomainException) throw error;
      this.logger.error(
        `Failed to cập nhật chỉ số thị trường: ${error instanceof Error ? error.message : error}`,
        error instanceof Error ? error.stack : undefined,
        this.constructor.name,
      );
      throw new InternalServerErrorException('Không thể cập nhật chỉ số thị trường. Vui lòng thử lại sau.');
    }
  }

  private async invalidateMarketCaches(): Promise<void> {
    await Promise.all([
      this.cache.invalidateByPrefix(CachePrefix.MARKET_REPORT),
      this.cache.invalidateByPrefix(CachePrefix.MARKET_TREND),
      this.cache.invalidateByPrefix(CachePrefix.MARKET_HEATMAP),
      this.cache.invalidateByPrefix(CachePrefix.MARKET_DISTRICT),
    ]);
  }
}
