import { d as db, b as backups, s as storageConfig } from '../../../admin/create-upload-progress-table/POST-C-OoiMoW.js';
import { eq, desc } from 'drizzle-orm';
import fs from 'fs';
import path from 'path';
import crypto from 'crypto';
import { pipeline } from 'stream/promises';
import { c as createStorageProvider } from '../../delete/_backupId_/DELETE-CSeC5rJf.js';
import { g as getBackupsDir, a as getTempDir, e as ensureDir } from '../../../auth/setup/POST-DYMc2GPx.js';

const ALGORITHM = "aes-256-gcm";
const KEY_LENGTH = 32;
const IV_LENGTH = 16;
const SALT_LENGTH = 32;
function generateEncryptionKey() {
  return crypto.randomBytes(KEY_LENGTH);
}
function deriveKeyFromPassword(password, salt) {
  const keySalt = crypto.randomBytes(SALT_LENGTH);
  const key = crypto.pbkdf2Sync(password, keySalt, 1e5, KEY_LENGTH, "sha256");
  return { key, salt: keySalt };
}
async function encryptFile(inputPath, outputPath, key) {
  const iv = crypto.randomBytes(IV_LENGTH);
  const cipher = crypto.createCipheriv(ALGORITHM, key, iv);
  await pipeline(
    fs.createReadStream(inputPath),
    cipher,
    fs.createWriteStream(outputPath)
  );
  const authTag = cipher.getAuthTag();
  return {
    algorithm: ALGORITHM,
    iv: iv.toString("base64"),
    authTag: authTag.toString("base64"),
    salt: ""
    // Salt is stored separately when using password-based encryption
  };
}
async function decryptFile(inputPath, outputPath, key, metadata) {
  const iv = Buffer.from(metadata.iv, "base64");
  const authTag = Buffer.from(metadata.authTag, "base64");
  const decipher = crypto.createDecipheriv(ALGORITHM, key, iv);
  decipher.setAuthTag(authTag);
  await pipeline(
    fs.createReadStream(inputPath),
    decipher,
    fs.createWriteStream(outputPath)
  );
}

async function handler(req, res) {
  try {
    const { backupId } = req.params;
    const { deviceId, encryptionKey } = req.query;
    if (!backupId) {
      return res.status(400).json({
        success: false,
        error: "Backup ID is required"
      });
    }
    if (!deviceId) {
      return res.status(400).json({
        success: false,
        error: "Device ID is required for authorization"
      });
    }
    if (!encryptionKey) {
      return res.status(400).json({
        success: false,
        error: "Encryption key is required"
      });
    }
    const backup = await db.select().from(backups).where(eq(backups.backupId, backupId)).limit(1);
    if (backup.length === 0) {
      return res.status(404).json({
        success: false,
        error: "Backup not found"
      });
    }
    const backupRecord = backup[0];
    if (backupRecord.deviceId !== deviceId) {
      return res.status(403).json({
        success: false,
        error: "Unauthorized: Backup belongs to different device"
      });
    }
    if (!backupRecord.encrypted) {
      return res.status(400).json({
        success: false,
        error: "Backup is not encrypted - use regular download endpoint"
      });
    }
    const configs = await db.select().from(storageConfig).where(eq(storageConfig.isActive, true)).orderBy(desc(storageConfig.createdAt)).limit(1);
    let storageType = "local";
    let storageConfigData = { basePath: getBackupsDir() };
    if (configs.length > 0) {
      storageType = configs[0].storageType;
      storageConfigData = JSON.parse(configs[0].config);
    }
    const storageProvider = createStorageProvider({
      type: storageType,
      config: storageConfigData
    });
    const storagePath = backupRecord.filePath;
    if (!storagePath) {
      return res.status(404).json({
        success: false,
        error: "Backup file path not found"
      });
    }
    const exists = await storageProvider.exists(storagePath);
    if (!exists) {
      return res.status(404).json({
        success: false,
        error: "Backup file not found in storage"
      });
    }
    const tempDir = path.join(getTempDir(), "decrypt");
    ensureDir(tempDir);
    const encryptedTempPath = path.join(tempDir, `encrypted_${Date.now()}_${crypto.randomBytes(8).toString("hex")}`);
    const encryptedBuffer = await storageProvider.download(storagePath);
    fs.writeFileSync(encryptedTempPath, encryptedBuffer);
    const metadata = {
      algorithm: backupRecord.encryptionAlgorithm || "aes-256-gcm",
      iv: backupRecord.encryptionIv || "",
      authTag: backupRecord.encryptionAuthTag || "",
      salt: backupRecord.encryptionSalt || ""
    };
    const decryptedTempPath = path.join(tempDir, `decrypted_${Date.now()}_${crypto.randomBytes(8).toString("hex")}`);
    try {
      const key = Buffer.from(encryptionKey, "base64");
      await decryptFile(encryptedTempPath, decryptedTempPath, key, metadata);
      const stats = fs.statSync(decryptedTempPath);
      const fileName = path.basename(storagePath).replace(".enc", "");
      res.setHeader("Content-Type", "application/octet-stream");
      res.setHeader("Content-Length", stats.size);
      res.setHeader("Content-Disposition", `attachment; filename="${fileName}"`);
      const fileStream = fs.createReadStream(decryptedTempPath);
      fileStream.pipe(res);
      fileStream.on("end", () => {
        if (fs.existsSync(decryptedTempPath)) {
          fs.unlinkSync(decryptedTempPath);
        }
        if (fs.existsSync(encryptedTempPath)) {
          fs.unlinkSync(encryptedTempPath);
        }
      });
      fileStream.on("error", (error) => {
        console.error("File stream error:", error);
        if (fs.existsSync(decryptedTempPath)) {
          fs.unlinkSync(decryptedTempPath);
        }
        if (fs.existsSync(encryptedTempPath)) {
          fs.unlinkSync(encryptedTempPath);
        }
        if (!res.headersSent) {
          res.status(500).json({
            success: false,
            error: "Failed to stream decrypted backup file"
          });
        }
      });
    } catch (decryptError) {
      if (fs.existsSync(decryptedTempPath)) {
        fs.unlinkSync(decryptedTempPath);
      }
      if (fs.existsSync(encryptedTempPath)) {
        fs.unlinkSync(encryptedTempPath);
      }
      throw decryptError;
    }
  } catch (error) {
    console.error("Backup download/decrypt error:", error);
    res.status(500).json({
      success: false,
      error: "Failed to download and decrypt backup",
      message: String(error)
    });
  }
}

export { deriveKeyFromPassword as d, encryptFile as e, generateEncryptionKey as g, handler as h };
