import * as crypto from 'crypto';
import * as fs from 'fs';
import { constants } from 'crypto';
import { Express } from 'express';

export class FileEncryptionUseCase {
  private RSA_PUBLIC_KEY: string;

  constructor(pemFilePath: string = './secrets/rsa_public.pem') {
    this.RSA_PUBLIC_KEY = fs.readFileSync(pemFilePath, 'utf-8');
  }

  async execute(file: Express.Multer.File, targetDir: string = './tmp'): Promise<string> {
    try {
      const fileExtension = `.${file.originalname.split('.').pop()}`;
      const fileBuffer = file.buffer;

      const extensionLengthBuffer = Buffer.alloc(4);
      extensionLengthBuffer.writeUInt32BE(fileExtension.length, 0);

      const extensionBuffer = Buffer.from(fileExtension, 'utf-8');

      const aesKey = crypto.randomBytes(32);
      const iv = crypto.randomBytes(16);

      const cipher = crypto.createCipheriv('aes-256-cbc', aesKey, iv);
      const encryptedFile = Buffer.concat([
        cipher.update(fileBuffer),
        cipher.final(),
      ]);

      const finalEncryptedFile = Buffer.concat([
        extensionLengthBuffer,
        extensionBuffer,
        iv,
        encryptedFile,
      ]);

      const encryptedAesKey = crypto.publicEncrypt(
        {
          key: this.RSA_PUBLIC_KEY,
          padding: constants.RSA_PKCS1_OAEP_PADDING,
        },
        aesKey
      );

      const encryptedFilePath = `${targetDir}/${file.originalname}.enc`;
      fs.writeFileSync(encryptedFilePath, finalEncryptedFile);

      const keyFilePath = `${targetDir}/${file.originalname}.key`;
      fs.writeFileSync(keyFilePath, encryptedAesKey);

      return encryptedFilePath;
    } catch (error) {
      console.error('❌ Error al cifrar el archivo:', error);
      throw new Error('Fallo en el cifrado del archivo');
    }
  }
}