const crypto = require('crypto');
const fs = require('fs');
const path = require('path');

async function readKeyFromFile(filePath) {
    try {
        await fs.promises.access(filePath, fs.constants.F_OK);
        return fs.promises.readFile(filePath); // Use asynchronous readFile
    } catch (error) {
        console.error('Error reading key file:', error);
        return null;
    }
}

// Paths to the key files remain the same
const IV_FILE_PATH = path.join(__dirname, '..', '..', 'iv.key');
const SECRET_KEY_FILE_PATH = path.join(__dirname, '..', '..', 'secret.key');

async function encryptFileInPlace(filePath) {
    // Await the resolution of these promises
    const IV = await readKeyFromFile(IV_FILE_PATH);
    const SECRET_KEY = await readKeyFromFile(SECRET_KEY_FILE_PATH);

    if (!IV || !SECRET_KEY) {
        throw new Error('Failed to load IV or Secret Key');
    }

    const tempEncryptedFilePath = filePath + '.enc'; // Temporary encrypted file
    return new Promise((resolve, reject) => {
        const cipher = crypto.createCipheriv('aes-256-cbc', Buffer.from(SECRET_KEY), IV);
        const input = fs.createReadStream(filePath);
        const output = fs.createWriteStream(tempEncryptedFilePath);

        input.pipe(cipher).pipe(output);

        output.on('finish', () => {
            fs.rename(tempEncryptedFilePath, filePath, (err) => {
                if (err) reject(err);
                else resolve('File encrypted successfully and replaced original.');
            });
        });
        output.on('error', reject);
    });
}

async function decryptFileInPlace(filePath) {
    // Await the resolution of these promises
    const IV = await readKeyFromFile(IV_FILE_PATH);
    const SECRET_KEY = await readKeyFromFile(SECRET_KEY_FILE_PATH);

    if (!IV || !SECRET_KEY) {
        throw new Error('Failed to load IV or Secret Key');
    }

    const tempDecryptedFilePath = filePath + '.dec'; // Temporary decrypted file
    return new Promise((resolve, reject) => {
        const decipher = crypto.createDecipheriv('aes-256-cbc', Buffer.from(SECRET_KEY), IV);
        const input = fs.createReadStream(filePath);
        const output = fs.createWriteStream(tempDecryptedFilePath);

        input.pipe(decipher).pipe(output);

        output.on('finish', () => {
            fs.rename(tempDecryptedFilePath, filePath, (err) => {
                if (err) reject(err);
                else resolve('File decrypted successfully and replaced original.');
            });
        });
        output.on('error', reject);
    });
}

function cryptForKey(content, key, decrypt = false) {
    const algorithm = 'aes-256-ctr';
    const secretKey = crypto.createHash('sha256').update(String(key)).digest('base64').substr(0, 32);
    let cipher;

    if (decrypt) {
        cipher = crypto.createDecipheriv(algorithm, secretKey, Buffer.alloc(16, 0)); // Using a zeroed IV for CTR
    } else {
        cipher = crypto.createCipheriv(algorithm, secretKey, Buffer.alloc(16, 0));
    }

    return Buffer.concat([cipher.update(content), cipher.final()]);
}

// Encrypts a file in place with a given key
async function encryptFileWithKey(filePath, key) {
    try {
        const fileContent = await fs.promises.readFile(filePath);
        const encryptedContent = cryptForKey(fileContent, key, false);
        await fs.promises.writeFile(filePath, encryptedContent);
        console.log(`File encrypted successfully: ${filePath}`);
    } catch (error) {
        console.error(`Error encrypting file: ${error.message}`);
    }
}

async function decryptFileWithKey(filePath, key) {
    try {
        const fileContent = await fs.promises.readFile(filePath);
        const decryptedContent = cryptForKey(fileContent, key, true);
        await fs.promises.writeFile(filePath, decryptedContent);
        console.log(`File decrypted successfully: ${filePath}`);
    } catch (error) {
        console.error(`Error decrypting file: ${error.message}`);
    }
}

module.exports = {
    encryptFileInPlace,
    decryptFileInPlace,
    encryptFileWithKey,
    decryptFileWithKey,
}
