import { Controller, Get, Query, UseGuards, } from '@nestjs/common'; import { QueryBus } from '@nestjs/cqrs'; import { ApiTags, ApiOperation, ApiResponse, ApiBearerAuth } from '@nestjs/swagger'; import { JwtAuthGuard } from '@modules/auth'; import { RequireQuota, QuotaGuard } from '@modules/subscriptions'; import { DistrictStatsDto } from '../../application/queries/get-district-stats/get-district-stats.handler'; import { GetDistrictStatsQuery } from '../../application/queries/get-district-stats/get-district-stats.query'; import { HeatmapDto } from '../../application/queries/get-heatmap/get-heatmap.handler'; import { GetHeatmapQuery } from '../../application/queries/get-heatmap/get-heatmap.query'; import { MarketReportDto } from '../../application/queries/get-market-report/get-market-report.handler'; import { GetMarketReportQuery } from '../../application/queries/get-market-report/get-market-report.query'; import { PriceTrendDto } from '../../application/queries/get-price-trend/get-price-trend.handler'; import { GetPriceTrendQuery } from '../../application/queries/get-price-trend/get-price-trend.query'; import { ValuationDto } from '../../application/queries/get-valuation/get-valuation.handler'; import { GetValuationQuery } from '../../application/queries/get-valuation/get-valuation.query'; import { GetDistrictStatsDto } from '../dto/get-district-stats.dto'; import { GetHeatmapDto } from '../dto/get-heatmap.dto'; import { GetMarketReportDto } from '../dto/get-market-report.dto'; import { GetPriceTrendDto } from '../dto/get-price-trend.dto'; import { GetValuationDto } from '../dto/get-valuation.dto'; @ApiTags('analytics') @Controller('analytics') export class AnalyticsController { constructor( private readonly queryBus: QueryBus, ) {} @ApiBearerAuth('JWT') @UseGuards(JwtAuthGuard, QuotaGuard) @RequireQuota('analytics_queries') @Get('market-report') @ApiOperation({ summary: 'Get market report for a city' }) @ApiResponse({ status: 200, description: 'Market report retrieved' }) @ApiResponse({ status: 403, description: 'Quota exceeded' }) async getMarketReport(@Query() dto: GetMarketReportDto): Promise { return this.queryBus.execute( new GetMarketReportQuery(dto.city, dto.period, dto.propertyType), ); } @ApiBearerAuth('JWT') @UseGuards(JwtAuthGuard, QuotaGuard) @RequireQuota('analytics_queries') @Get('price-trend') @ApiOperation({ summary: 'Get price trend for a district' }) @ApiResponse({ status: 200, description: 'Price trend data retrieved' }) @ApiResponse({ status: 403, description: 'Quota exceeded' }) async getPriceTrend(@Query() dto: GetPriceTrendDto): Promise { return this.queryBus.execute( new GetPriceTrendQuery(dto.district, dto.city, dto.propertyType, dto.periods), ); } @ApiBearerAuth('JWT') @UseGuards(JwtAuthGuard, QuotaGuard) @RequireQuota('analytics_queries') @Get('heatmap') @ApiOperation({ summary: 'Get price heatmap for a city' }) @ApiResponse({ status: 200, description: 'Heatmap data retrieved' }) @ApiResponse({ status: 403, description: 'Quota exceeded' }) async getHeatmap(@Query() dto: GetHeatmapDto): Promise { return this.queryBus.execute( new GetHeatmapQuery(dto.city, dto.period), ); } @ApiBearerAuth('JWT') @UseGuards(JwtAuthGuard, QuotaGuard) @RequireQuota('analytics_queries') @Get('district-stats') @ApiOperation({ summary: 'Get statistics by district' }) @ApiResponse({ status: 200, description: 'District statistics retrieved' }) @ApiResponse({ status: 403, description: 'Quota exceeded' }) async getDistrictStats(@Query() dto: GetDistrictStatsDto): Promise { return this.queryBus.execute( new GetDistrictStatsQuery(dto.city, dto.period), ); } @ApiBearerAuth('JWT') @UseGuards(JwtAuthGuard, QuotaGuard) @RequireQuota('analytics_queries') @Get('valuation') @ApiOperation({ summary: 'Get automated property valuation (AVM)' }) @ApiResponse({ status: 200, description: 'Valuation estimate retrieved' }) @ApiResponse({ status: 400, description: 'Invalid parameters — provide propertyId or (lat, lng, areaM2)' }) @ApiResponse({ status: 403, description: 'Quota exceeded' }) async getValuation(@Query() dto: GetValuationDto): Promise { return this.queryBus.execute( new GetValuationQuery(dto.propertyId, dto.latitude, dto.longitude, dto.areaM2, dto.propertyType), ); } }