import {
  Body,
  Controller,
  Delete,
  Get,
  HttpCode,
  HttpStatus,
  Param,
  Post,
  Query,
  Req,
  UseGuards,
} from '@nestjs/common';
import { type CommandBus, type QueryBus } from '@nestjs/cqrs';
import { ApiTags, ApiOperation, ApiResponse, ApiBearerAuth } from '@nestjs/swagger';
import { JwtAuthGuard } from '@modules/auth';
import { RequireQuota, QuotaGuard } from '@modules/subscriptions';
import { DeleteReportCommand } from '../../application/commands/delete-report/delete-report.command';
import { GenerateReportCommand } from '../../application/commands/generate-report/generate-report.command';
import { type GenerateReportResult } from '../../application/commands/generate-report/generate-report.handler';
import { GetReportQuery } from '../../application/queries/get-report/get-report.query';
import { type ListReportsResult } from '../../application/queries/list-reports/list-reports.handler';
import { ListReportsQuery } from '../../application/queries/list-reports/list-reports.query';
import { type ReportEntity } from '../../domain/entities/report.entity';
import { type GenerateReportDto } from '../dto/generate-report.dto';
import { type ListReportsDto } from '../dto/list-reports.dto';

interface AuthenticatedRequest {
  user: { sub: string };
}

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

  @Post('generate')
  @ApiBearerAuth('JWT')
  @UseGuards(JwtAuthGuard, QuotaGuard)
  @RequireQuota('reports_generated')
  @ApiOperation({ summary: 'Tạo báo cáo AI (async)' })
  @ApiResponse({ status: 201, description: 'Report generation started' })
  async generate(
    @Body() dto: GenerateReportDto,
    @Req() req: AuthenticatedRequest,
  ): Promise<GenerateReportResult> {
    return this.commandBus.execute(
      new GenerateReportCommand(req.user.sub, dto.type, dto.title, dto.params),
    );
  }

  @Get()
  @ApiBearerAuth('JWT')
  @UseGuards(JwtAuthGuard)
  @ApiOperation({ summary: 'Danh sách báo cáo của tôi' })
  @ApiResponse({ status: 200, description: 'List of reports' })
  async list(
    @Query() dto: ListReportsDto,
    @Req() req: AuthenticatedRequest,
  ) {
    const result: ListReportsResult = await this.queryBus.execute(
      new ListReportsQuery(req.user.sub, dto.type, dto.limit, dto.offset),
    );
    return {
      data: result.reports.map((r) => this.toResponse(r)),
      total: result.total,
    };
  }

  @Get(':id')
  @ApiBearerAuth('JWT')
  @UseGuards(JwtAuthGuard)
  @ApiOperation({ summary: 'Chi tiết báo cáo' })
  @ApiResponse({ status: 200, description: 'Report details' })
  async getById(
    @Param('id') id: string,
    @Req() req: AuthenticatedRequest,
  ) {
    const report: ReportEntity = await this.queryBus.execute(
      new GetReportQuery(id, req.user.sub),
    );
    return this.toResponse(report);
  }

  @Get(':id/status')
  @ApiBearerAuth('JWT')
  @UseGuards(JwtAuthGuard)
  @ApiOperation({ summary: 'Trạng thái tạo báo cáo' })
  @ApiResponse({ status: 200, description: 'Report status' })
  async getStatus(
    @Param('id') id: string,
    @Req() req: AuthenticatedRequest,
  ) {
    const report: ReportEntity = await this.queryBus.execute(
      new GetReportQuery(id, req.user.sub),
    );
    return {
      id: report.id,
      status: report.status,
      errorMsg: report.errorMsg,
      pdfUrl: report.pdfUrl,
    };
  }

  @Delete(':id')
  @ApiBearerAuth('JWT')
  @UseGuards(JwtAuthGuard)
  @HttpCode(HttpStatus.NO_CONTENT)
  @ApiOperation({ summary: 'Xóa báo cáo' })
  @ApiResponse({ status: 204, description: 'Report deleted' })
  async delete(
    @Param('id') id: string,
    @Req() req: AuthenticatedRequest,
  ): Promise<void> {
    await this.commandBus.execute(new DeleteReportCommand(id, req.user.sub));
  }

  private toResponse(report: ReportEntity) {
    return {
      id: report.id,
      type: report.type,
      title: report.title,
      params: report.params,
      content: report.content,
      pdfUrl: report.pdfUrl,
      status: report.status,
      errorMsg: report.errorMsg,
      createdAt: report.createdAt.toISOString(),
      updatedAt: report.updatedAt.toISOString(),
    };
  }
}
