import { Inject, InternalServerErrorException } from '@nestjs/common';
import { QueryHandler, type IQueryHandler } from '@nestjs/cqrs';
import { DomainException, CacheService, CachePrefix, CacheTTL, LoggerService } from '@modules/shared';
import { type ListingSearchItem } from '../../../domain/repositories/listing-read.dto';
import { LISTING_REPOSITORY, type IListingRepository, type PaginatedResult } from '../../../domain/repositories/listing.repository';
import { SearchListingsQuery } from './search-listings.query';

@QueryHandler(SearchListingsQuery)
export class SearchListingsHandler implements IQueryHandler<SearchListingsQuery> {
  constructor(
    @Inject(LISTING_REPOSITORY) private readonly listingRepo: IListingRepository,
    private readonly cacheService: CacheService,
    private readonly logger: LoggerService,
  ) {}

  async execute(query: SearchListingsQuery): Promise<PaginatedResult<ListingSearchItem>> {
    try {
      const cacheKey = CacheService.buildKey(
        CachePrefix.SEARCH,
        query.status,
        query.transactionType,
        query.propertyType,
        query.city,
        query.district,
        query.minPrice?.toString(),
        query.maxPrice?.toString(),
        query.minArea?.toString(),
        query.maxArea?.toString(),
        query.bedrooms?.toString(),
        String(query.page),
        String(query.limit),
        query.sortBy,
        query.newSince?.toISOString(),
        query.order,
      );

      return this.cacheService.getOrSet(
        cacheKey,
        async () =>
          this.listingRepo.search({
            status: query.status,
            transactionType: query.transactionType,
            propertyType: query.propertyType,
            city: query.city,
            district: query.district,
            minPrice: query.minPrice,
            maxPrice: query.maxPrice,
            minArea: query.minArea,
            maxArea: query.maxArea,
            bedrooms: query.bedrooms,
            page: query.page,
            limit: query.limit,
            sortBy: query.sortBy,
            newSince: query.newSince,
            order: query.order,
          }),
        CacheTTL.SEARCH_RESULTS,
        'listing_search',
      );
    } catch (error) {
      if (error instanceof DomainException) throw error;
      this.logger.error(
        `Failed to search listings: ${error instanceof Error ? error.message : error}`,
        error instanceof Error ? error.stack : undefined,
        this.constructor.name,
      );
      throw new InternalServerErrorException('Không thể tìm kiếm tin đăng bất động sản');
    }
  }
}
