import {
  Body,
  Controller,
  Delete,
  Get,
  Param,
  Post,
  Query,
  UseGuards,
} from '@nestjs/common';
// eslint-disable-next-line @typescript-eslint/consistent-type-imports -- NestJS DI requires value imports for emitDecoratorMetadata
import { CommandBus, QueryBus } from '@nestjs/cqrs';
import {
  ApiTags,
  ApiOperation,
  ApiResponse,
  ApiBearerAuth,
  ApiParam,
} from '@nestjs/swagger';
import { type JwtPayload, CurrentUser, JwtAuthGuard } from '@modules/auth';
import { CreateReviewCommand } from '../../application/commands/create-review/create-review.command';
import { type CreateReviewResult } from '../../application/commands/create-review/create-review.handler';
import { DeleteReviewCommand } from '../../application/commands/delete-review/delete-review.command';
import { GetAverageRatingQuery } from '../../application/queries/get-average-rating/get-average-rating.query';
import { GetReviewsByTargetQuery } from '../../application/queries/get-reviews-by-target/get-reviews-by-target.query';
import { GetReviewsByUserQuery } from '../../application/queries/get-reviews-by-user/get-reviews-by-user.query';
import { type ReviewItemData, type ReviewStatsData } from '../../domain/repositories/review-read.dto';
import { type PaginatedResult } from '../../domain/repositories/review.repository';
import { CreateReviewDto } from '../dto/create-review.dto';
import { ListReviewsByTargetDto, ReviewStatsDto } from '../dto/list-reviews.dto';

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

  @ApiBearerAuth('JWT')
  @ApiOperation({ summary: 'Create a review' })
  @ApiResponse({ status: 201, description: 'Review created successfully' })
  @ApiResponse({ status: 400, description: 'Validation error' })
  @ApiResponse({ status: 401, description: 'Unauthorized' })
  @ApiResponse({ status: 409, description: 'Already reviewed this target' })
  @UseGuards(JwtAuthGuard)
  @Post()
  async createReview(
    @Body() dto: CreateReviewDto,
    @CurrentUser() user: JwtPayload,
  ): Promise<CreateReviewResult> {
    return this.commandBus.execute(
      new CreateReviewCommand(
        user.sub,
        dto.targetType,
        dto.targetId,
        dto.rating,
        dto.comment ?? null,
      ),
    );
  }

  @ApiOperation({ summary: 'List reviews by target' })
  @ApiResponse({ status: 200, description: 'Paginated list of reviews' })
  @Get()
  async getReviewsByTarget(
    @Query() dto: ListReviewsByTargetDto,
  ): Promise<PaginatedResult<ReviewItemData>> {
    return this.queryBus.execute(
      new GetReviewsByTargetQuery(
        dto.targetType,
        dto.targetId,
        dto.page ?? 1,
        dto.limit ?? 20,
      ),
    );
  }

  @ApiOperation({ summary: 'Get aggregate rating stats for a target' })
  @ApiResponse({ status: 200, description: 'Rating statistics' })
  @Get('stats')
  async getStats(
    @Query() dto: ReviewStatsDto,
  ): Promise<ReviewStatsData> {
    return this.queryBus.execute(
      new GetAverageRatingQuery(dto.targetType, dto.targetId),
    );
  }

  @ApiBearerAuth('JWT')
  @ApiOperation({ summary: 'Get reviews by authenticated user' })
  @ApiResponse({ status: 200, description: 'Paginated list of user reviews' })
  @ApiResponse({ status: 401, description: 'Unauthorized' })
  @UseGuards(JwtAuthGuard)
  @Get('me')
  async getMyReviews(
    @CurrentUser() user: JwtPayload,
    @Query('page') page?: number,
    @Query('limit') limit?: number,
  ): Promise<PaginatedResult<ReviewItemData>> {
    return this.queryBus.execute(
      new GetReviewsByUserQuery(user.sub, page ?? 1, limit ?? 20),
    );
  }

  @ApiBearerAuth('JWT')
  @ApiOperation({ summary: 'Delete own review' })
  @ApiParam({ name: 'id', description: 'Review ID' })
  @ApiResponse({ status: 200, description: 'Review deleted' })
  @ApiResponse({ status: 401, description: 'Unauthorized' })
  @ApiResponse({ status: 403, description: 'Cannot delete another user\'s review' })
  @ApiResponse({ status: 404, description: 'Review not found' })
  @UseGuards(JwtAuthGuard)
  @Delete(':id')
  async deleteReview(
    @Param('id') id: string,
    @CurrentUser() user: JwtPayload,
  ): Promise<{ deleted: boolean }> {
    await this.commandBus.execute(new DeleteReviewCommand(id, user.sub));
    return { deleted: true };
  }
}
