import { Inject, NotFoundException, InternalServerErrorException } from '@nestjs/common';
import { QueryHandler, type IQueryHandler } from '@nestjs/cqrs';
import { DomainException, CacheService, CachePrefix, CacheTTL, LoggerService } from '@modules/shared';
import {
  MARKET_INDEX_REPOSITORY,
  type IMarketIndexRepository,
  type ListingVolumeWardResult,
} from '../../../domain/repositories/market-index.repository';
import { GetListingVolumeWardQuery } from './get-listing-volume-ward.query';

export type ListingVolumeWardDto = ListingVolumeWardResult;

@QueryHandler(GetListingVolumeWardQuery)
export class GetListingVolumeWardHandler implements IQueryHandler<GetListingVolumeWardQuery> {
  constructor(
    @Inject(MARKET_INDEX_REPOSITORY) private readonly marketIndexRepo: IMarketIndexRepository,
    private readonly cache: CacheService,
    private readonly logger: LoggerService,
  ) {}

  async execute(query: GetListingVolumeWardQuery): Promise<ListingVolumeWardDto> {
    try {
      const cacheKey = CacheService.buildKey(
        CachePrefix.MARKET_HEATMAP,
        'ward-volume',
        query.wardId,
        query.period,
      );

      const result = await this.cache.getOrSet(
        cacheKey,
        async () => this.marketIndexRepo.getListingVolumeByWard(query.wardId, query.period),
        CacheTTL.HEATMAP_WARD,
        'listing-volume-ward',
      );

      if (!result) {
        throw new NotFoundException(
          `Không tìm thấy dữ liệu khối lượng tin đăng cho phường "${query.wardId}" trong kỳ "${query.period}".`,
        );
      }

      return result;
    } catch (error) {
      if (error instanceof DomainException || error instanceof NotFoundException) throw error;
      this.logger.error(
        `Failed to truy vấn khối lượng tin đăng theo phường: ${error instanceof Error ? error.message : error}`,
        error instanceof Error ? error.stack : undefined,
        this.constructor.name,
      );
      throw new InternalServerErrorException(
        'Không thể truy vấn dữ liệu khối lượng tin đăng theo phường. Vui lòng thử lại sau.',
      );
    }
  }
}
