import {
  Controller,
  Get,
  Post,
  Query,
  UseGuards,
} from '@nestjs/common';
import { CommandBus, QueryBus } from '@nestjs/cqrs';
import {
  ApiTags,
  ApiOperation,
  ApiResponse,
  ApiBearerAuth,
} from '@nestjs/swagger';
import { Roles, JwtAuthGuard, RolesGuard } from '@modules/auth';
import { EndpointRateLimit, EndpointRateLimitGuard } from '@modules/shared';
import { ReindexAllCommand } from '../../application/commands/reindex-all/reindex-all.command';
import { type ReindexResult } from '../../application/commands/reindex-all/reindex-all.handler';
import { GeoSearchQuery } from '../../application/queries/geo-search/geo-search.query';
import { SearchPropertiesQuery } from '../../application/queries/search-properties/search-properties.query';
import { type SearchResult } from '../../domain/repositories/search.repository';
import { GeoSearchDto } from '../dto/geo-search.dto';
import { SearchPropertiesDto } from '../dto/search-properties.dto';

@ApiTags('search')
@Controller('search')
export class SearchController {
  constructor(
    private readonly commandBus: CommandBus,
    private readonly queryBus: QueryBus,
  ) {}

  @EndpointRateLimit({ limit: 30, windowSeconds: 60, keyStrategy: 'user' })
  @UseGuards(EndpointRateLimitGuard)
  @Get()
  @ApiOperation({ summary: 'Search properties', description: 'Public full-text and faceted property search' })
  @ApiResponse({ status: 200, description: 'Search results returned successfully' })
  async search(@Query() dto: SearchPropertiesDto): Promise<SearchResult> {
    return this.queryBus.execute(
      new SearchPropertiesQuery(
        dto.q,
        dto.propertyType,
        dto.transactionType,
        dto.priceMin,
        dto.priceMax,
        dto.areaMin,
        dto.areaMax,
        dto.bedrooms,
        dto.district,
        dto.city,
        dto.sortBy,
        dto.page,
        dto.perPage,
        dto.featured,
      ),
    );
  }

  @EndpointRateLimit({ limit: 30, windowSeconds: 60, keyStrategy: 'user' })
  @UseGuards(EndpointRateLimitGuard)
  @Get('geo')
  @ApiOperation({ summary: 'Geo search properties', description: 'Public geographic radius property search' })
  @ApiResponse({ status: 200, description: 'Geo search results returned successfully' })
  async geoSearch(@Query() dto: GeoSearchDto): Promise<SearchResult> {
    return this.queryBus.execute(
      new GeoSearchQuery(
        dto.lat,
        dto.lng,
        dto.radiusKm,
        dto.propertyType,
        dto.transactionType,
        dto.priceMin,
        dto.priceMax,
        dto.sortBy,
        dto.page,
        dto.perPage,
      ),
    );
  }

  @UseGuards(JwtAuthGuard, RolesGuard)
  @Roles('ADMIN')
  @Post('reindex')
  @ApiBearerAuth('JWT')
  @ApiOperation({ summary: 'Reindex all properties', description: 'Admin-only endpoint to trigger a full reindex' })
  @ApiResponse({ status: 201, description: 'Reindex completed successfully' })
  @ApiResponse({ status: 401, description: 'Unauthorized — missing or invalid JWT' })
  @ApiResponse({ status: 403, description: 'Forbidden — requires ADMIN role' })
  async reindex(): Promise<ReindexResult> {
    return this.commandBus.execute(new ReindexAllCommand());
  }
}
