import { Body, Controller, Delete, Get, Param, Patch, Post, Query, UseGuards, } from '@nestjs/common'; import { type CommandBus, type QueryBus } from '@nestjs/cqrs'; import { ApiTags, ApiOperation, ApiResponse, ApiBearerAuth, ApiParam, } from '@nestjs/swagger'; import { type JwtPayload, CurrentUser, JwtAuthGuard } from '@modules/auth'; import { CreateSavedSearchCommand } from '../../application/commands/create-saved-search/create-saved-search.command'; import { type CreateSavedSearchResult } from '../../application/commands/create-saved-search/create-saved-search.handler'; import { DeleteSavedSearchCommand } from '../../application/commands/delete-saved-search/delete-saved-search.command'; import { UpdateSavedSearchCommand } from '../../application/commands/update-saved-search/update-saved-search.command'; import { type UpdateSavedSearchResult } from '../../application/commands/update-saved-search/update-saved-search.handler'; import { type SavedSearchDetail } from '../../application/queries/get-saved-search/get-saved-search.handler'; import { GetSavedSearchQuery } from '../../application/queries/get-saved-search/get-saved-search.query'; import { type SavedSearchListResult } from '../../application/queries/get-saved-searches/get-saved-searches.handler'; import { GetSavedSearchesQuery } from '../../application/queries/get-saved-searches/get-saved-searches.query'; import { type CreateSavedSearchDto, type UpdateSavedSearchDto, type SavedSearchListDto } from '../dto/saved-search.dto'; @ApiTags('saved-searches') @ApiBearerAuth('JWT') @UseGuards(JwtAuthGuard) @Controller('saved-searches') export class SavedSearchController { constructor( private readonly commandBus: CommandBus, private readonly queryBus: QueryBus, ) {} @Post() @ApiOperation({ summary: 'Lưu tìm kiếm', description: 'Lưu bộ lọc tìm kiếm để nhận thông báo khi có kết quả mới' }) @ApiResponse({ status: 201, description: 'Tìm kiếm đã được lưu' }) @ApiResponse({ status: 400, description: 'Dữ liệu không hợp lệ' }) @ApiResponse({ status: 401, description: 'Chưa đăng nhập' }) @ApiResponse({ status: 403, description: 'Đã đạt giới hạn gói đăng ký' }) async create( @Body() dto: CreateSavedSearchDto, @CurrentUser() user: JwtPayload, ): Promise { return this.commandBus.execute( new CreateSavedSearchCommand( user.sub, dto.name, dto.filters, dto.alertEnabled ?? true, ), ); } @Get() @ApiOperation({ summary: 'Danh sách tìm kiếm đã lưu', description: 'Lấy danh sách tìm kiếm đã lưu của người dùng' }) @ApiResponse({ status: 200, description: 'Danh sách tìm kiếm đã lưu' }) @ApiResponse({ status: 401, description: 'Chưa đăng nhập' }) async list( @Query() dto: SavedSearchListDto, @CurrentUser() user: JwtPayload, ): Promise { return this.queryBus.execute( new GetSavedSearchesQuery(user.sub, dto.page ?? 1, dto.limit ?? 20), ); } @Get(':id') @ApiOperation({ summary: 'Chi tiết tìm kiếm đã lưu', description: 'Lấy chi tiết một tìm kiếm đã lưu' }) @ApiParam({ name: 'id', description: 'ID tìm kiếm đã lưu' }) @ApiResponse({ status: 200, description: 'Chi tiết tìm kiếm đã lưu' }) @ApiResponse({ status: 401, description: 'Chưa đăng nhập' }) @ApiResponse({ status: 404, description: 'Không tìm thấy' }) async getById( @Param('id') id: string, @CurrentUser() user: JwtPayload, ): Promise { return this.queryBus.execute( new GetSavedSearchQuery(id, user.sub), ); } @Patch(':id') @ApiOperation({ summary: 'Cập nhật tìm kiếm đã lưu', description: 'Cập nhật tên, bộ lọc hoặc trạng thái thông báo' }) @ApiParam({ name: 'id', description: 'ID tìm kiếm đã lưu' }) @ApiResponse({ status: 200, description: 'Đã cập nhật' }) @ApiResponse({ status: 401, description: 'Chưa đăng nhập' }) @ApiResponse({ status: 404, description: 'Không tìm thấy' }) async update( @Param('id') id: string, @Body() dto: UpdateSavedSearchDto, @CurrentUser() user: JwtPayload, ): Promise { return this.commandBus.execute( new UpdateSavedSearchCommand( id, user.sub, dto.name, dto.filters, dto.alertEnabled, ), ); } @Delete(':id') @ApiOperation({ summary: 'Xóa tìm kiếm đã lưu', description: 'Xóa một tìm kiếm đã lưu' }) @ApiParam({ name: 'id', description: 'ID tìm kiếm đã lưu' }) @ApiResponse({ status: 200, description: 'Đã xóa' }) @ApiResponse({ status: 401, description: 'Chưa đăng nhập' }) @ApiResponse({ status: 404, description: 'Không tìm thấy' }) async delete( @Param('id') id: string, @CurrentUser() user: JwtPayload, ): Promise<{ deleted: boolean }> { return this.commandBus.execute( new DeleteSavedSearchCommand(id, user.sub), ); } }