import {
  Controller,
  Post,
  UseInterceptors,
  UploadedFile,
  Param,
  UseGuards,
  BadRequestException,
  Delete,
  Get,
  Res,
  HttpStatus,
  Body,
} from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import { ApiTags, ApiOperation, ApiConsumes, ApiBody, ApiResponse } from '@nestjs/swagger';
import { Response } from 'express';
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
import { RbacGuard } from '../auth/guards/rbac.guard';
import { Permissions } from '../auth/decorators/permissions.decorator';
import { UploadService } from '../services/upload.service';
import * as fs from 'fs';
import * as path from 'path';

@ApiTags('Uploads')
@Controller('uploads')
@UseGuards(JwtAuthGuard, RbacGuard)
export class UploadController {
  constructor(private readonly uploadService: UploadService) {}

  @Post(':type')
  @ApiOperation({ summary: 'Upload a file' })
  @ApiConsumes('multipart/form-data')
  @ApiBody({
    schema: {
      type: 'object',
      properties: {
        file: {
          type: 'string',
          format: 'binary',
        },
      },
    },
  })
  @ApiResponse({ status: 201, description: 'File uploaded successfully' })
  @ApiResponse({ status: 400, description: 'Invalid file type or size' })
  @UseInterceptors(FileInterceptor('file'))
  @Permissions('admin:all', 'manager:content', 'manager:products')
  async uploadFile(
    @Param('type') type: string,
    @UploadedFile() file: Express.Multer.File,
  ) {
    if (!file) {
      throw new BadRequestException('No file uploaded');
    }

    const config = this.uploadService.getUploadConfig(type);
    const fileUrl = this.uploadService.getFileUrl(file.filename, type);

    return {
      success: true,
      message: 'File uploaded successfully',
      data: {
        filename: file.filename,
        originalName: file.originalname,
        mimetype: file.mimetype,
        size: file.size,
        url: fileUrl,
        type: type,
      },
    };
  }

  @Delete(':type/:filename')
  @ApiOperation({ summary: 'Delete a file' })
  @ApiResponse({ status: 200, description: 'File deleted successfully' })
  @ApiResponse({ status: 404, description: 'File not found' })
  @Permissions('admin:all', 'manager:content', 'manager:products')
  async deleteFile(
    @Param('type') type: string,
    @Param('filename') filename: string,
  ) {
    const filePath = this.uploadService.getFilePath(filename, type);
    
    if (!fs.existsSync(filePath)) {
      throw new BadRequestException('File not found');
    }

    await this.uploadService.deleteFile(filePath);

    return {
      success: true,
      message: 'File deleted successfully',
    };
  }

  @Get(':type/:filename')
  @ApiOperation({ summary: 'Get a file' })
  @ApiResponse({ status: 200, description: 'File retrieved successfully' })
  @ApiResponse({ status: 404, description: 'File not found' })
  async getFile(
    @Param('type') type: string,
    @Param('filename') filename: string,
    @Res() res: Response,
  ) {
    const filePath = this.uploadService.getFilePath(filename, type);
    
    if (!fs.existsSync(filePath)) {
      return res.status(HttpStatus.NOT_FOUND).json({
        success: false,
        message: 'File not found',
      });
    }

    const stat = fs.statSync(filePath);
    const ext = path.extname(filename).toLowerCase();
    
    // Set appropriate content type based on file extension
    let contentType = 'application/octet-stream';
    if (['.jpg', '.jpeg', '.png', '.gif', '.webp', '.svg'].includes(ext)) {
      contentType = `image/${ext.substring(1)}`;
    } else if (ext === '.pdf') {
      contentType = 'application/pdf';
    } else if (ext === '.txt') {
      contentType = 'text/plain';
    }

    res.setHeader('Content-Type', contentType);
    res.setHeader('Content-Length', stat.size);
    res.setHeader('Cache-Control', 'public, max-age=31536000'); // Cache for 1 year

    const fileStream = fs.createReadStream(filePath);
    fileStream.pipe(res);
  }

  @Post(':type/base64')
  @ApiOperation({ summary: 'Upload a base64 image' })
  @ApiBody({
    schema: {
      type: 'object',
      properties: {
        image: {
          type: 'string',
          description: 'Base64 encoded image data',
        },
        originalName: {
          type: 'string',
          description: 'Original filename (optional)',
        },
      },
      required: ['image'],
    },
  })
  @ApiResponse({ status: 201, description: 'Image uploaded successfully' })
  @ApiResponse({ status: 400, description: 'Invalid image data' })
  @Permissions('admin:all', 'manager:content', 'manager:products')
  async uploadBase64Image(
    @Param('type') type: string,
    @Body() body: { image: string; originalName?: string },
  ) {
    if (!body.image) {
      throw new BadRequestException('No image data provided');
    }

    const filename = await this.uploadService.saveBase64Image(
      body.image,
      type,
      body.originalName,
    );

    const fileUrl = this.uploadService.getFileUrl(filename, type);

    return {
      success: true,
      message: 'Image uploaded successfully',
      data: {
        filename,
        url: fileUrl,
        type: type,
      },
    };
  }
} 