import {
  Controller,
  Get,
  Post,
  Body,
  Param,
  UseInterceptors,
  UploadedFile,
  BadRequestException,
  Logger,
  UploadedFiles,
  Res,
  HttpException,
  HttpStatus,
} from '@nestjs/common';
import { ReportService } from './report.service';
import { CreateReportDto } from './dto/report.dto';
import { Report } from './entity/report.entity';
import { ApiTags, ApiOperation, ApiResponse, ApiConsumes, ApiBody } from '@nestjs/swagger';
import { ReportResponseDto } from './dto/report-response.dto';
import { TicketResponseDto } from 'modules/ticket/dto/response-ticket.dto';
import { FileInterceptor, FilesInterceptor } from '@nestjs/platform-express';
import { CreateCommentDto } from 'modules/ticket/dto/create-comment.dto';
import { Comment } from 'modules/ticket/entities/comment.entity';
import axios from 'axios';
import { Response } from 'express'; // Added missing import

@ApiTags('Reports')
@Controller({ path: 'report', version: '1' })
export class ReportController {
  private readonly logger = new Logger(ReportController.name);
  constructor(private readonly reportService: ReportService) {}

  @Post()
  @ApiOperation({ summary: 'Create a new report' })
  @ApiResponse({ status: 201, description: 'Report successfully created', type: ReportResponseDto })
  @ApiBody({
    type: CreateReportDto,
  })
  async create(@Body() createReportDto: CreateReportDto): Promise<ReportResponseDto> {
    return this.reportService.create(createReportDto);
  }

  @Post('anonymous')
  @ApiOperation({ summary: 'Submit anonymous threat report' })
  @ApiResponse({ status: 201, description: 'Threat report submitted successfully' })
  @ApiConsumes('multipart/form-data')
  @ApiBody({
    schema: {
      type: 'object',
      properties: {
        responses: { type: 'string' },
        reportType: { type: 'string' },
        files: {
          type: 'array',
          items: { type: 'string', format: 'binary' },
        },
        userDetails: { type: 'string', description: 'JSON stringified user details' },
      },
    },
  })
  @UseInterceptors(FilesInterceptor('files', 2))
  async submitAnonymousReport(@Body() body: any, @UploadedFiles() files?: Express.Multer.File[]): Promise<any> {
    return this.reportService.submitAnonymousReport(body, files);
  }

  @Get()
  @ApiOperation({ summary: 'Retrieve all reports' })
  @ApiResponse({ status: 200, description: 'List of reports', type: [ReportResponseDto] })
  async findAll(): Promise<ReportResponseDto[]> {
    return this.reportService.findAll();
  }

  @Get(':id')
  @ApiOperation({ summary: 'Retrieve a specific report' })
  @ApiResponse({ status: 200, description: 'Report found', type: Report })
  @ApiResponse({ status: 404, description: 'Report not found' })
  async findOne(@Param('id') id: number): Promise<ReportResponseDto> {
    return this.reportService.findOne(id);
  }

  @Get('user/:userId/tokens')
  @ApiOperation({ summary: 'Get all report tokens associated with a user' })
  @ApiResponse({ status: 200, description: 'List of report tokens', type: [String] })
  @ApiResponse({ status: 400, description: 'Invalid user ID' })
  async findReportTokensByUserId(@Param('userId') userId: string): Promise<string[]> {
    const userIdNum = parseInt(userId, 10);
    if (isNaN(userIdNum)) {
      throw new BadRequestException('User ID must be a number');
    }

    return this.reportService.findReportTokensByUserId(userIdNum);
  }

  @Get(':ticketToken/ticket/comments')
  @ApiOperation({ summary: 'Get comments for a ticket' })
  @ApiResponse({ status: 200, description: 'Comments retrieved successfully.', type: [TicketResponseDto] })
  @ApiResponse({ status: 404, description: 'Ticket not found.' })
  async getCommentsForReportTicket(@Param('ticketToken') ticketToken: string) {
    return this.reportService.getCommentsForReportTicket(ticketToken);
  }

  @Get('/token/:tokenId')
  @ApiOperation({ summary: 'verify a specific report' })
  @ApiResponse({ status: 200, description: 'Report found', type: Report })
  @ApiBody({
    type: String,
  })
  @ApiResponse({ status: 404, description: 'Report not found' })
  async verifyReportToken(@Param('tokenId') tokenId: string): Promise<ReportResponseDto> {
    return this.reportService.findReportByToken(tokenId);
  }

  // add comment to report ticket
  @Post(':ticketToken/ticket/comments')
  @UseInterceptors(FileInterceptor('attachment'))
  @ApiOperation({ summary: 'Add a comment to a ticket' })
  @ApiResponse({ status: 201, description: 'Comment added successfully.', type: TicketResponseDto })
  @ApiResponse({ status: 404, description: 'Ticket not found.' })
  @ApiConsumes('multipart/form-data')
  @ApiBody({
    schema: {
      type: 'object',
      properties: {
        content: { type: 'string' },
        role: { type: 'string' },
        attachment: { type: 'string', format: 'binary' },
      },
      required: ['content'],
    },
  })
  async addCommentToReportTicket(
    @Param('ticketToken') ticketToken: string,
    @Body() createCommentDto: CreateCommentDto,
    @UploadedFile() file: Express.Multer.File,
  ) {
    return this.reportService.addCommentToReportTicket(ticketToken, createCommentDto, 0, file);
  }

  @Get(':ticketToken/ticket/comments/:commentId/seen')
  @ApiOperation({ summary: 'Mark a comment as seen' })
  @ApiResponse({ status: 200, description: 'Comment marked as seen successfully.' })
  @ApiResponse({ status: 404, description: 'Comment not found.' })
  async markCommentAsSeen(@Param('ticketToken') ticketToken: string, @Param('commentId') commentId: number): Promise<Comment> {
    return this.reportService.markCommentAsSeen(ticketToken, commentId);
  }

  // Route for downloading PDF by user ID
  @Get('user/:userId/ticket/download')
  @ApiOperation({ summary: 'Download PDF report by user ID' })
  @ApiResponse({ status: 200, description: 'Returns the PDF file for download' })
  @ApiResponse({ status: 404, description: 'Report or PDF not found' })
  async downloadPdfByUserId(@Param('userId') userId: string, @Res() res: Response): Promise<void> {
    try {
      // Find the report by userId
      const report = await this.reportService.findByUserId(Number(userId));

      if (!report || !report.pdfUrl) {
        throw new HttpException('PDF report not found for this user', HttpStatus.NOT_FOUND);
      }

      // Get the PDF file from Cloudinary
      const response = await axios.get(report.pdfUrl, { responseType: 'arraybuffer' });

      // Set response headers for file download
      res.setHeader('Content-Type', 'application/pdf');
      res.setHeader('Content-Disposition', `attachment; filename="report-${userId}.pdf"`);

      // Send the PDF data
      res.send(response.data);
    } catch (error) {
      throw new HttpException(error.message || 'Failed to download PDF', error.status || HttpStatus.INTERNAL_SERVER_ERROR);
    }
  }

  // Route for downloading PDF by ticket token
  @Get(':ticketToken/ticket/download')
  @ApiOperation({ summary: 'Download PDF report by ticket token' })
  @ApiResponse({ status: 200, description: 'Returns the PDF file for download' })
  @ApiResponse({ status: 404, description: 'Report or PDF not found' })
  async downloadPdfByTicketToken(@Param('ticketToken') ticketToken: string, @Res() res: Response): Promise<void> {

    try {
      const pdfUrl = await this.reportService.getPdfByTicketToken(ticketToken);

      // Get the PDF file from Cloudinary
      const response = await axios.get(pdfUrl, { responseType: 'arraybuffer' });

      // Set response headers for file download
      res.setHeader('Content-Type', 'application/pdf');
      res.setHeader('Content-Disposition', `attachment; filename="report-${ticketToken}.pdf"`);

      // Send the PDF data
      res.send(response.data);
    } catch (error) {
      this.logger.error("Error downloading PDF", error);
      throw new HttpException(error.message || 'Failed to download PDF', error.status || HttpStatus.INTERNAL_SERVER_ERROR);
    }
  }

  // For completeness, maintaining original PDF endpoints but with proper redirect implementation
  @Get(':id/pdf')
  @ApiOperation({ summary: 'Get PDF for a specific report' })
  @ApiResponse({ status: 200, description: 'Redirects to the PDF file' })
  @ApiResponse({ status: 404, description: 'Report or PDF not found' })
  async getPdfByReportId(@Param('id') id: number, @Res() res: Response): Promise<void> {
    try {
      const pdfUrl = await this.reportService.getPdfByReportId(id);
      res.status(302).location(pdfUrl).send();
    } catch (error) {
      throw new HttpException(error.message, HttpStatus.NOT_FOUND);
    }
  }
}
