import { AuthGuard, type Viewer } from '@authentication/auth.guard'
import { ViewerParam } from '@authentication/viewer.decorator'
import { Controller, Get, Param, Post, Res, UseGuards } from '@nestjs/common'
import type { FileId } from '@types'
import { toFileId } from '@types'

import { FastifyReply } from 'fastify'

import { UploadedFileData } from './uploaded-file.decorator'
import { UploadGuard } from './upload.guard'
import { UploadService } from './upload.service'
import type { UploadedFileDataPayload } from './upload.types'

@UseGuards(AuthGuard)
@Controller('upload')
export class UploadController {
  constructor(private readonly uploadService: UploadService) {}

  @UseGuards(
    UploadGuard({
      maxFileSizeBytes: 30 * 1024 * 1024,
    }),
  )
  @Post('')
  upload(@UploadedFileData() uploadData: UploadedFileDataPayload) {
    return {
      success: true,
      result: {
        file: uploadData.file,
      },
    }
  }

  @Get(':fileId/download')
  async downloadById(
    @Param('fileId') fileIdRaw: string,
    @ViewerParam() viewer: Viewer,
    @Res({ passthrough: true }) res: FastifyReply,
  ): Promise<void> {
    const fileId: FileId = toFileId(fileIdRaw)
    const file = await this.uploadService.getStoredFileRecord({ fileId, authorization: viewer })
    const buffer = await this.uploadService.getBufferFromFileRecord({ fileId, location: file.url })

    const filename = file.name || `file-${fileId}`
    const asciiFilename = filename.replaceAll(/[^A-Za-z0-9._-]/g, '_')
    const encodedFilename = encodeURIComponent(filename)

    res.type(file.mimetype || 'application/octet-stream')
    res.header('Content-Disposition', `attachment; filename="${asciiFilename}"; filename*=UTF-8''${encodedFilename}`)
    res.header('Access-Control-Expose-Headers', 'Content-Disposition')
    res.send(buffer)
  }
}
