import { Public, Role } from '@hed-hog/api';
import { getLocaleText, Locale } from '@hed-hog/api-locale';
import { Pagination } from '@hed-hog/api-pagination';
import {
  Body,
  Controller,
  Delete,
  forwardRef,
  Get,
  Inject,
  Param,
  ParseIntPipe,
  Post,
  Put,
  Req,
  Res,
  UploadedFile,
  UseInterceptors,
} from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import { Request, Response } from 'express';
import { readFileSync } from 'fs';
import Handlebars from 'handlebars';
import { join } from 'path';
import { DeleteDTO } from './dto/delete.dto';
import { UploadFileDTO } from './dto/upload.dto';
import { FileService } from './file.service';

@Role()
@Controller('file')
export class FileController {
  constructor(
    @Inject(forwardRef(() => FileService))
    private readonly fileService: FileService,
  ) {}

  @Get()
  async list(@Pagination() paginationParams) {
    return this.fileService.getFiles(paginationParams);
  }

  @Get(':id')
  async show(@Param('id', ParseIntPipe) id) {
    return this.fileService.get(id);
  }

  @Put('open/:id')
  async getTempOpenURL(@Param('id', ParseIntPipe) id: number) {
    return {
      url: await this.fileService.tempOpenURL(
        (await this.fileService.get(id)).path,
      ),
    };
  }

  @Put('download/:id')
    async getTempURL(
      @Param('id', ParseIntPipe) id: number,
      @Req() req: Request,
    ) {
      const file = await this.fileService.get(id);
      const token = this.fileService.createDownloadToken(file.path, 3600);
      const origin = `${req.protocol}://${req.get('host')}`;

    return {
        url: `${origin}/file/download/${encodeURIComponent(token)}`,
    };
  }

  @Public()
  @Get('download/:token')
  async download(
    @Param('token') token: string,
    @Res() res: Response,
    @Locale() locale: string,
  ) {

    try {

      const { stream, filename, mimetype, size } =
        await this.fileService.download(locale, token);

      const encodedFilename = encodeURIComponent(filename);
      res.set({
        'Content-Type': mimetype || 'application/octet-stream',
        'Content-Disposition':
          `attachment; filename="${filename}"; ` +
          `filename*=UTF-8''${encodedFilename}`,
      });

      if (typeof size === 'number') {
        res.set('Content-Length', `${size}`);
      }

      stream.pipe(res);
      return;

    } catch (error:any) {
      // Buscar traduções
      const errorTitle = getLocaleText('file.download.error_title', locale);
      const errorMessage = getLocaleText('file.download.error_message', locale);
      const errorDetailsLabel = getLocaleText('file.download.error_details', locale);
      const goBackText = getLocaleText('file.download.go_back', locale);
      
      // Ler e compilar template
      const templatePath = join(__dirname, 'templates', 'download-error.html');
      const templateSource = readFileSync(templatePath, 'utf-8');
      const template = Handlebars.compile(templateSource);
      
      // Renderizar template com dados
      const html = template({
        locale: locale || 'en',
        errorTitle,
        errorMessage,
        errorDetailsLabel,
        errorDetails: error?.message || 'Unknown error occurred',
        goBackText,
      });
      
      res.status(400).set('Content-Type', 'text/html').send(html);
      return;
    }
  }

  @Public()
  @Get('open/:token')
  async open(
    @Param('token') token: string,
    @Res() res: Response,
    @Locale() locale: string,
  ) {

    try {

      const numericId = Number(token);
      const isNumericId = Number.isInteger(numericId) && String(numericId) === token;

      if (isNumericId && numericId > 0) {
        const { stream, filename, mimetype, size } =
          await this.fileService.openById(locale, numericId);

        const encodedFilename = encodeURIComponent(filename);

        res.set({
          'Content-Type': mimetype || 'application/octet-stream',
          'Content-Disposition':
            `inline; filename="${filename}"; ` +
            `filename*=UTF-8''${encodedFilename}`,
        });

        if (typeof size === 'number') {
          res.set('Content-Length', `${size}`);
        }

        stream.pipe(res);
        return;
      }

      const { stream, filename, mimetype, size } =
        await this.fileService.download(locale, token);

      const encodedFilename = encodeURIComponent(filename);

      res.set({
        'Content-Type': mimetype || 'application/octet-stream',
        'Content-Disposition':
          `inline; filename="${filename}"; ` +
          `filename*=UTF-8''${encodedFilename}`,
      });

      if (typeof size === 'number') {
        res.set('Content-Length', `${size}`);
      }

      stream.pipe(res);
      return;

    } catch (error:any) {
      const errorTitle = getLocaleText('file.download.error_title', locale);
      const errorMessage = getLocaleText('file.download.error_message', locale);
      const errorDetailsLabel = getLocaleText('file.download.error_details', locale);
      const goBackText = getLocaleText('file.download.go_back', locale);

      const templatePath = join(__dirname, 'templates', 'download-error.html');
      const templateSource = readFileSync(templatePath, 'utf-8');
      const template = Handlebars.compile(templateSource);

      const html = template({
        locale: locale || 'en',
        errorTitle,
        errorMessage,
        errorDetailsLabel,
        errorDetails: error?.message || 'Unknown error occurred',
        goBackText,
      });

      res.status(400).set('Content-Type', 'text/html').send(html);
      return;
    }
  }

  @Post()
  @UseInterceptors(FileInterceptor('file'))
  async upload(
    @UploadedFile() file: MulterFile,
    @Body() body: UploadFileDTO,
  ) {
    const destination = body.destination || 'files';
    return this.fileService.upload(destination, file);
  }

  @Delete()
  async delete(@Body() data: DeleteDTO, @Locale() locale: string) {
    return this.fileService.delete(locale, data);
  }
}
