"use strict";
/**
 * ⚛️ Atomic File Writer
 * All-or-nothing file operations - Zero slippage design
 *
 * Strategy:
 * 1. Write to .tmp file first
 * 2. Validate the write succeeded
 * 3. Atomic rename (OS-level atomic operation)
 * 4. If ANY step fails, original file is untouched
 *
 * User NEVER sees partial state
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.atomicWrite = atomicWrite;
exports.safeRead = safeRead;
exports.fileExists = fileExists;
exports.getFileModifiedTime = getFileModifiedTime;
const fs_1 = require("fs");
const event_emitter_1 = require("../core/events/event-emitter");
const mirror_events_1 = require("../core/events/mirror-events");
/**
 * Atomic file write
 * Implements all-or-nothing operation
 *
 * @param filePath - Target file path
 * @param content - Content to write
 * @param projectPath - Project root (for events)
 */
async function atomicWrite(filePath, content, projectPath = process.cwd()) {
    const tmpPath = `${filePath}.tmp`;
    const backupPath = `${filePath}.backup`;
    try {
        // EMIT: Starting write
        event_emitter_1.mirrorEvents.emitMirrorEvent((0, mirror_events_1.createMirrorEvent)(mirror_events_1.MirrorEventType.FILE_WRITE, {
            file: filePath,
            step: 'start'
        }, { projectPath }));
        // Step 1: Create backup of existing file (if exists)
        const fileExists = await fs_1.promises.access(filePath).then(() => true).catch(() => false);
        if (fileExists) {
            await fs_1.promises.copyFile(filePath, backupPath);
            event_emitter_1.mirrorEvents.emitMirrorEvent((0, mirror_events_1.createMirrorEvent)(mirror_events_1.MirrorEventType.FILE_BACKUP, {
                original: filePath,
                backup: backupPath
            }, { projectPath }));
        }
        // Step 2: Write to temporary file
        await fs_1.promises.writeFile(tmpPath, content, 'utf-8');
        // Step 3: Validate the temporary file
        const writtenContent = await fs_1.promises.readFile(tmpPath, 'utf-8');
        if (writtenContent !== content) {
            throw new Error('File validation failed: written content does not match');
        }
        // Step 4: Atomic rename (OS-level atomic operation)
        await fs_1.promises.rename(tmpPath, filePath);
        // Step 5: Clean up backup
        if (fileExists) {
            await fs_1.promises.unlink(backupPath).catch(() => {
                // Ignore backup cleanup errors
            });
        }
        // EMIT: Success
        event_emitter_1.mirrorEvents.emitMirrorEvent((0, mirror_events_1.createMirrorEvent)(mirror_events_1.MirrorEventType.FILE_WRITE, {
            file: filePath,
            step: 'complete',
            success: true
        }, { projectPath }));
    }
    catch (error) {
        // Cleanup temporary file if it exists
        await fs_1.promises.unlink(tmpPath).catch(() => {
            // Ignore cleanup errors
        });
        // Restore from backup if we have one
        const backupExists = await fs_1.promises.access(backupPath).then(() => true).catch(() => false);
        if (backupExists) {
            await fs_1.promises.rename(backupPath, filePath).catch(() => {
                // If restore fails, emit error but don't throw
                event_emitter_1.mirrorEvents.emitMirrorEvent((0, mirror_events_1.createMirrorEvent)(mirror_events_1.MirrorEventType.ERROR, {
                    message: 'Failed to restore backup',
                    file: filePath
                }, { projectPath }));
            });
        }
        // EMIT: Error
        event_emitter_1.mirrorEvents.emitMirrorEvent((0, mirror_events_1.createMirrorEvent)(mirror_events_1.MirrorEventType.ERROR, {
            message: error instanceof Error ? error.message : String(error),
            file: filePath,
            recoverable: backupExists
        }, { projectPath }));
        throw error;
    }
}
/**
 * Safe file read with error handling
 */
async function safeRead(filePath, projectPath = process.cwd()) {
    try {
        event_emitter_1.mirrorEvents.emitMirrorEvent((0, mirror_events_1.createMirrorEvent)(mirror_events_1.MirrorEventType.FILE_READ, {
            file: filePath
        }, { projectPath }));
        const content = await fs_1.promises.readFile(filePath, 'utf-8');
        return content;
    }
    catch (error) {
        event_emitter_1.mirrorEvents.emitMirrorEvent((0, mirror_events_1.createMirrorEvent)(mirror_events_1.MirrorEventType.ERROR, {
            message: `Failed to read ${filePath}: ${error instanceof Error ? error.message : String(error)}`,
            file: filePath
        }, { projectPath }));
        throw error;
    }
}
/**
 * Check if file exists
 */
async function fileExists(filePath) {
    return fs_1.promises.access(filePath).then(() => true).catch(() => false);
}
/**
 * Get file modification time
 */
async function getFileModifiedTime(filePath) {
    try {
        const stats = await fs_1.promises.stat(filePath);
        return stats.mtime;
    }
    catch {
        return null;
    }
}
//# sourceMappingURL=atomic-write.js.map