import {
  Controller,
  Get,
  Post,
  Body,
  Patch,
  Param,
  Delete,
  UseInterceptors,
  UploadedFiles,
  Req,
  SetMetadata,
  UseGuards,
  Res,
  StreamableFile,
} from '@nestjs/common';
import { FilesService } from './files.service';

import { ApiBearerAuth, ApiBody, ApiConsumes, ApiTags } from '@nestjs/swagger';
import { FilesInterceptor } from '@nestjs/platform-express';
import { diskStorage } from 'multer';
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
import { AuthGuard } from '../auth/guards/auth.guard';
import { extname, join } from 'path';
import { createReadStream } from 'fs';
import { Response } from 'express';

@Controller('files')
@ApiTags('files')
export class FilesController {
  constructor(private readonly filesService: FilesService) {}

  @Post()
  @ApiBearerAuth()
  @SetMetadata('permissions', ['create_file'])
  @UseGuards(JwtAuthGuard, AuthGuard)
  @UseInterceptors(
    FilesInterceptor('files', 10, {
      storage: diskStorage({
        destination: './uploads/',
        filename: (req, file, cb) => {
          const randomName = Array(32)
            .fill(null)
            .map(() => Math.round(Math.random() * 16).toString(16))
            .join('');
          cb(null, `${randomName}${extname(file.originalname)}`);
        },
      }),
    }),
  )
  @ApiConsumes('multipart/form-data')
  @ApiBody({
    schema: {
      type: 'object',
      properties: {
        files: {
          type: 'array',
          items: {
            type: 'string',
            format: 'binary',
          },
        },
      },
    },
  })
  create(@UploadedFiles() files: Array<Express.Multer.File>, @Req() req: any) {
    return this.filesService.create(files, req.user.id);
  }

  @ApiBearerAuth()
  @SetMetadata('permissions', ['view_file'])
  @UseGuards(JwtAuthGuard, AuthGuard)
  @Get()
  findAll(@Req() req: any) {
    return this.filesService.findAll(req.query);
  }

  @ApiBearerAuth()
  @SetMetadata('permissions', ['view_file'])
  @UseGuards(JwtAuthGuard, AuthGuard)
  @Get('edit/:id')
  findOne(@Param('id') id: string) {
    return this.filesService.findOne(id);
  }

  @ApiBearerAuth()
  @SetMetadata('permissions', ['edit_file'])
  @UseGuards(JwtAuthGuard, AuthGuard)
  @Patch('edit/:id')
  @ApiBody({
    schema: {
      type: 'object',
      properties: {
        alt: {
          type: 'string',
        },
      },
    },
  })
  update(@Param('id') id: string, @Body() data) {
    return this.filesService.update(id, data);
  }

  @ApiBearerAuth()
  @SetMetadata('permissions', ['destroy_file'])
  @UseGuards(JwtAuthGuard, AuthGuard)
  @Delete(':id')
  remove(@Param('id') id: string) {
    return this.filesService.remove(id);
  }

  @Get(':id')
  async stream(
    @Param('id') id: string,
    @Res({ passthrough: true }) res: Response,
  ): Promise<StreamableFile> {
    const getFile = await this.filesService.streamFile(id);
    const file = createReadStream(
      join(process.cwd(), '//uploads//' + getFile.path),
    );
    res.set({
      'Content-Type': getFile.mimetype,
      'Content-Disposition': `attachment; filename="${getFile.path}"`,
    });
    return new StreamableFile(file);
  }
}
