/**
 * Config-Audit Rollback Engine
 * Restores configuration from backup with checksum verification.
 * Zero external dependencies.
 */

import { readFile, writeFile, readdir, stat, rm } from 'node:fs/promises';
import { join } from 'node:path';
import { getBackupDir, parseManifest, checksum } from './lib/backup.mjs';

/**
 * List all available backups.
 * @returns {Promise<{ backups: object[] }>}
 */
export async function listBackups() {
  const backupRoot = getBackupDir();
  const backups = [];

  let entries;
  try {
    entries = await readdir(backupRoot, { withFileTypes: true });
  } catch {
    return { backups: [] };
  }

  for (const entry of entries) {
    if (!entry.isDirectory()) continue;

    const backupPath = join(backupRoot, entry.name);
    const manifestPath = join(backupPath, 'manifest.yaml');

    try {
      const manifestContent = await readFile(manifestPath, 'utf-8');
      const manifest = parseManifest(manifestContent);

      backups.push({
        id: entry.name,
        createdAt: manifest.created_at,
        files: manifest.files.map(f => ({
          originalPath: f.originalPath,
          backupPath: f.backupPath,
          checksum: f.checksum,
          sizeBytes: f.sizeBytes,
        })),
      });
    } catch {
      // Skip backups without valid manifest
      continue;
    }
  }

  // Sort newest first
  backups.sort((a, b) => b.id.localeCompare(a.id));

  return { backups };
}

/**
 * Restore files from a backup.
 * @param {string} backupId
 * @param {object} [opts]
 * @param {boolean} [opts.dryRun=false]
 * @param {boolean} [opts.verify=true]
 * @returns {Promise<{ restored: object[], failed: object[] }>}
 */
export async function restoreBackup(backupId, opts = {}) {
  const verify = opts.verify !== false;
  const backupRoot = getBackupDir();
  const backupPath = join(backupRoot, backupId);
  const manifestPath = join(backupPath, 'manifest.yaml');

  // Read manifest
  let manifestContent;
  try {
    manifestContent = await readFile(manifestPath, 'utf-8');
  } catch {
    throw new Error(`Backup not found: ${backupId}`);
  }

  const manifest = parseManifest(manifestContent);
  const restored = [];
  const failed = [];

  for (const fileEntry of manifest.files) {
    const backupFilePath = join(backupPath, fileEntry.backupPath);

    if (opts.dryRun) {
      restored.push({
        originalPath: fileEntry.originalPath,
        status: 'dry-run',
      });
      continue;
    }

    try {
      // Read backup file
      const content = await readFile(backupFilePath);

      // Verify checksum before restoring
      if (verify) {
        const hash = checksum(content);
        if (hash !== fileEntry.checksum) {
          failed.push({
            originalPath: fileEntry.originalPath,
            status: 'checksum-mismatch',
            error: `Expected ${fileEntry.checksum}, got ${hash}`,
          });
          continue;
        }
      }

      // Write to original path
      await writeFile(fileEntry.originalPath, content);

      // Verify after write
      if (verify) {
        const written = await readFile(fileEntry.originalPath);
        const writtenHash = checksum(written);
        if (writtenHash !== fileEntry.checksum) {
          failed.push({
            originalPath: fileEntry.originalPath,
            status: 'checksum-mismatch',
            error: 'Checksum mismatch after write',
          });
          continue;
        }
      }

      restored.push({
        originalPath: fileEntry.originalPath,
        status: 'restored',
      });
    } catch (err) {
      failed.push({
        originalPath: fileEntry.originalPath,
        status: 'failed',
        error: err.message,
      });
    }
  }

  return { restored, failed };
}

/**
 * Delete a backup directory.
 * @param {string} backupId
 * @returns {Promise<{ deleted: boolean, error?: string }>}
 */
export async function deleteBackup(backupId) {
  const backupRoot = getBackupDir();
  const backupPath = join(backupRoot, backupId);

  try {
    await stat(backupPath);
  } catch {
    return { deleted: false, error: `Backup not found: ${backupId}` };
  }

  try {
    await rm(backupPath, { recursive: true, force: true });
    return { deleted: true };
  } catch (err) {
    return { deleted: false, error: err.message };
  }
}
