import {
  Controller,
  Get,
  Post,
  Param,
  UseGuards,
  UploadedFile,
  UseInterceptors,
  Res,
  Delete,
  Query,
  StreamableFile,
} from '@nestjs/common';
import { FileService, FileResult, SharpFit } from './file.service';
import {
  ApiBearerAuth,
  ApiBody,
  ApiConsumes,
  ApiOkResponse,
  ApiOperation,
  ApiTags,
} from '@nestjs/swagger';
import { AuthGuard } from '@nestjs/passport';
import { RequestUser } from 'src/common/request-user';
import { FileResponseDTO } from './dto/upload-file-response-dto';
import { Express, Response } from 'express';
import { FileInterceptor } from '@nestjs/platform-express';
import { ConfigService } from '@nestjs/config';
import { UserAccessDTO } from './dto/user-access-dto';
import { lookup as mimeLookup } from 'mime-types';
import { OptionalJwtAuthGuard } from '../common/guards/optional-jwt.auth.guard';
import { ApiError } from '../common/error/api-error';
import { ApiErrorCodes } from '../common/error/api-error-codes';
import { FileUploadLogicInterceptor } from './file-upload-logic-interceptor';

@ApiTags('file')
@Controller('file')
@UseGuards(OptionalJwtAuthGuard)
export class FileController {
  constructor(
    private readonly fileService: FileService,
    private configService: ConfigService,
  ) {}

  /*
  Token:
{
  "user": "abc",
  "store": "def",
  "access": [
     { "dir": null, "quota": 1024 (в байтах), "maxSize": 1024 (в байтах), "rights": "rw" (возможные значения - r, w, rw)}
     { "dir": "avc", "quota": 512, "maxSize": 1024 (в байтах),"rights": "r" },
     ... 
  ]
}
  */

  @Get(':store/:id')
  @ApiOperation({
    summary: 'Get file',
  })
  async getFile(
    @Param('store') store: string,
    @Param('id') id: string,
    @Res({ passthrough: true }) response: Response,
    @RequestUser() user: UserAccessDTO | null,
    @Query() { download }: { download: string },
  ) {
    const file = await this.fileService.getFile(store, id, user);
    const type = mimeLookup(file.title) || 'application/octet-stream';
    response.setHeader('Content-Type', type);
    if (download) {
      const encoded = encodeURIComponent(file.title);
      response.setHeader(
        'Content-Disposition',
        `attachment; filename*=UTF-8''${encoded}; filename="${encoded}"`,
      );
    }
    const date_and_year = new Date();
    date_and_year.setFullYear(date_and_year.getFullYear() + 1);
    response.setHeader('Expires', date_and_year.toUTCString());
    response.setHeader('Cache-Control', `private, max-age=31536000, immutable`);
    return new StreamableFile(file.stream);
  }

  @Get(':store/:id/thumb/:width/:height/:fit')
  @ApiOperation({
    summary: 'Get thumb file',
  })
  async getThumbFile(
    @Param('store') store: string,
    @Param('id') id: string,
    @Param('width') width: string,
    @Param('height') height: string,
    @Param('fit') fit: SharpFit,
    @Res({ passthrough: true }) response: Response,
    @RequestUser() user: UserAccessDTO | null,
  ) {
    const file = await this.fileService.getThumbFile(
      store,
      id,
      user,
      parseInt(width),
      parseInt(height),
      fit,
    );
    const file_type = mimeLookup(file.title) || 'application/octet-stream';
    response.setHeader('Content-Type', file_type);
    const date_and_year = new Date();
    date_and_year.setFullYear(date_and_year.getFullYear() + 1);
    response.setHeader('Expires', date_and_year.toUTCString());
    response.setHeader('Cache-Control', `private, max-age=31536000, immutable`);
    return new StreamableFile(file.stream);
  }

  @Post(':store/upload')
  @ApiOperation({
    summary: 'Загрузка файла',
  })
  @ApiOkResponse({
    description: '',
    type: FileResponseDTO,
  })
  @UseInterceptors(FileUploadLogicInterceptor)
  @ApiConsumes('multipart/form-data')
  //@ApiParam({ name: 'dir', required: false })
  @ApiBody({
    required: true,
    schema: {
      type: 'object',
      required: ['file'],
      properties: {
        file: {
          type: 'string',
          format: 'binary',
        },
      },
    },
  })
  @UseGuards(AuthGuard(['jwt']))
  @ApiBearerAuth()
  async uploadFile(
    @UploadedFile() file: Express.Multer.File,
    @RequestUser() user: UserAccessDTO | null,
    @Param('store') store: string,
    //@Param('dir') dir: string | null,
  ): Promise<FileResult> {
    if (!user) {
      throw new ApiError('You must be logged in', ApiErrorCodes.ACCESS_DENIED);
    }
    const res = await this.fileService.saveUploadedFile(
      file,
      user,
      store,
      null,
      false,
    );
    return res;
  }

  @Delete(':store/:id')
  @ApiOperation({
    summary: 'Delete file',
  })
  //@ApiParam({ name: 'dir', required: false })
  @UseGuards(AuthGuard(['jwt']))
  @ApiBearerAuth()
  async deleteFile(
    @RequestUser() user: UserAccessDTO | null,
    @Param('store') store: string,
    @Param('id') id: string,
  ): Promise<void> {
    if (!user) {
      throw new ApiError('You must be logged in', ApiErrorCodes.ACCESS_DENIED);
    }
    await this.fileService.deleteFile(user, store, id);
  }
}
