import { Inject, InternalServerErrorException } from '@nestjs/common';
import { type IQueryHandler, QueryHandler } from '@nestjs/cqrs';
import { CacheService, CachePrefix, CacheTTL, DomainException, LoggerService } from '@modules/shared';
import {
  SEARCH_REPOSITORY,
  type ISearchRepository,
  type SearchResult,
} from '../../../domain/repositories/search.repository';
import { SearchPropertiesQuery } from './search-properties.query';

@QueryHandler(SearchPropertiesQuery)
export class SearchPropertiesHandler implements IQueryHandler<SearchPropertiesQuery> {
  constructor(
    @Inject(SEARCH_REPOSITORY) private readonly searchRepo: ISearchRepository,
    private readonly cache: CacheService,
    private readonly logger: LoggerService,
  ) {}

  async execute(query: SearchPropertiesQuery): Promise<SearchResult> {
    try {
      const filters: string[] = ['status:=ACTIVE'];

      if (query.propertyType) {
        filters.push(`propertyType:=${query.propertyType}`);
      }
      if (query.transactionType) {
        filters.push(`transactionType:=${query.transactionType}`);
      }
      if (query.priceMin !== undefined && query.priceMax !== undefined) {
        filters.push(`priceVND:[${query.priceMin}..${query.priceMax}]`);
      } else if (query.priceMin !== undefined) {
        filters.push(`priceVND:>=${query.priceMin}`);
      } else if (query.priceMax !== undefined) {
        filters.push(`priceVND:<=${query.priceMax}`);
      }
      if (query.areaMin !== undefined && query.areaMax !== undefined) {
        filters.push(`areaM2:[${query.areaMin}..${query.areaMax}]`);
      } else if (query.areaMin !== undefined) {
        filters.push(`areaM2:>=${query.areaMin}`);
      } else if (query.areaMax !== undefined) {
        filters.push(`areaM2:<=${query.areaMax}`);
      }
      if (query.bedrooms !== undefined) {
        filters.push(`bedrooms:>=${query.bedrooms}`);
      }
      if (query.district) {
        filters.push(`district:=${query.district}`);
      }
      if (query.city) {
        filters.push(`city:=${query.city}`);
      }
      if (query.featured === true) {
        filters.push(`isFeatured:=1`);
      } else if (query.featured === false) {
        filters.push(`isFeatured:=0`);
      }

      const searchParams = {
        query: query.query,
        filterBy: filters.join(' && '),
        sortBy: query.sortBy,
        page: query.page,
        perPage: query.perPage,
      };

      const cacheKey = CacheService.buildKey(
        CachePrefix.SEARCH,
        query.query ?? '*',
        query.propertyType,
        query.transactionType,
        query.district,
        query.city,
        query.page,
        query.perPage,
        query.priceMin,
        query.priceMax,
        query.areaMin,
        query.areaMax,
        query.bedrooms,
        query.sortBy,
        query.featured === undefined ? undefined : String(query.featured),
      );

      return this.cache.getOrSet(
        cacheKey,
        () => this.searchRepo.search(searchParams),
        CacheTTL.SEARCH_RESULTS,
        'search',
      );
    } catch (error) {
      if (error instanceof DomainException) throw error;
      this.logger.error(
        `Failed to search properties: ${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 bất động sản');
    }
  }
}
