// Standalone error handler for headless/server mode (no Electron dependency)
import * as fs from "fs";
import * as path from "path";
import { serverLogger } from "./logger.js";
export class ErrorHandler {
    errorLogs = [];
    maxLogs = 1000;
    errorLogPath;
    recoveryStrategies = new Map();
    constructor(){
        // Use CONFIG_PATH environment variable or default to ~/.sound-app
        const userDataPath = process.env.CONFIG_PATH || path.join(process.env.HOME || '/tmp', '.sound-app');
        // Ensure directory exists
        if (!fs.existsSync(userDataPath)) {
            fs.mkdirSync(userDataPath, {
                recursive: true
            });
        }
        this.errorLogPath = path.join(userDataPath, "error.log");
        // Set up global error handlers
        this.setupGlobalHandlers();
        // Register default recovery strategies
        this.registerDefaultRecoveryStrategies();
    }
    setupGlobalHandlers() {
        // Handle uncaught exceptions
        process.on("uncaughtException", (error)=>{
            // Handle EPIPE errors gracefully (broken pipe/socket closed)
            if (error.message.includes("EPIPE") || error.code === "EPIPE") {
                // Silently ignore EPIPE errors - they're common and not critical
                return; // Exit early, no logging or dialog needed
            }
            // Only log non-EPIPE errors
            console.error("=================================================");
            console.error("[ErrorHandler] UNCAUGHT EXCEPTION!");
            console.error("[ErrorHandler] Message:", error.message);
            console.error("[ErrorHandler] Stack trace:");
            console.error(error.stack);
            console.error("=================================================");
            // Try to get more context about what caused this
            if (error.message.includes("Cannot read properties of undefined")) {
                console.error("[ErrorHandler] This is a property access error. Check the stack trace above.");
            }
            this.logError(error, {
                operation: "uncaughtException",
                component: "global"
            });
            // In headless mode, just log the error - no dialog
            serverLogger.error("Unexpected error occurred:", error.message);
            // Try to recover
            this.attemptRecovery("uncaughtException");
        });
        // Handle unhandled promise rejections
        process.on("unhandledRejection", (reason)=>{
            const error = reason instanceof Error ? reason : new Error(String(reason));
            this.logError(error, {
                operation: "unhandledRejection",
                component: "global"
            });
        });
    }
    registerDefaultRecoveryStrategies() {
        // Database recovery
        this.recoveryStrategies.set("database", async ()=>{
            const { getDatabase, closeDatabase } = await import("../server/database.js");
            try {
                closeDatabase();
                // Wait a bit before reopening
                await new Promise((resolve)=>setTimeout(resolve, 1000));
                getDatabase(); // This will reinitialize the database
            } catch (error) {
                serverLogger.error("Database recovery failed:", error);
            }
        });
        // Scanner recovery
        this.recoveryStrategies.set("scanner", async ()=>{
            // Scanner recovery would be handled by the main process
            // This is just a placeholder as AppState is not a singleton
            serverLogger.info("Scanner recovery requested");
        });
        // Network recovery
        this.recoveryStrategies.set("network", async ()=>{
            // Clear any pending requests
            // This would be implemented based on your network layer
            serverLogger.info("Attempting network recovery...");
        });
        // Metadata processor recovery
        this.recoveryStrategies.set("metadata", async ()=>{
            const { getMetadataProcessor } = await import("../server/routes.js");
            const processor = getMetadataProcessor();
            if (processor) {
                processor.stop();
                await new Promise((resolve)=>setTimeout(resolve, 1000));
                processor.start();
            }
        });
    }
    /**
   * Log an error with context
   */ logError(error, context, level = "error") {
        const errorLog = {
            timestamp: Date.now(),
            message: typeof error === "string" ? error : error.message,
            stack: typeof error === "object" ? error.stack : undefined,
            context,
            level
        };
        // Add to in-memory logs
        this.errorLogs.push(errorLog);
        if (this.errorLogs.length > this.maxLogs) {
            this.errorLogs = this.errorLogs.slice(-this.maxLogs);
        }
        // Write to file
        this.writeToFile(errorLog);
        // Console output for development
        if (process.env.NODE_ENV === "development") {
            serverLogger.error(`[${level.toUpperCase()}] ${context.operation}:`, error);
        }
    }
    /**
   * Write error to log file
   */ writeToFile(errorLog) {
        try {
            const logLine = JSON.stringify(errorLog) + "\n";
            fs.appendFileSync(this.errorLogPath, logLine, "utf8");
            // Rotate log if too large (10MB)
            const stats = fs.statSync(this.errorLogPath);
            if (stats.size > 10 * 1024 * 1024) {
                const backupPath = this.errorLogPath + ".old";
                fs.renameSync(this.errorLogPath, backupPath);
            }
        } catch (error) {
            // Silently fail - we don't want logging to cause more errors
            serverLogger.error("Failed to write error log:", error);
        }
    }
    /**
   * Attempt recovery based on error context
   */ async attemptRecovery(operation) {
        const strategy = this.recoveryStrategies.get(operation);
        if (!strategy) {
            serverLogger.info(`No recovery strategy for operation: ${operation}`);
            return false;
        }
        try {
            await strategy();
            serverLogger.info(`Recovery successful for: ${operation}`);
            return true;
        } catch (error) {
            serverLogger.error(`Recovery failed for ${operation}:`, error);
            return false;
        }
    }
    /**
   * Register a custom recovery strategy
   */ registerRecoveryStrategy(operation, strategy) {
        this.recoveryStrategies.set(operation, strategy);
    }
    /**
   * Get recent errors
   */ getRecentErrors(count = 50) {
        return this.errorLogs.slice(-count);
    }
    /**
   * Clear error logs
   */ clearLogs() {
        this.errorLogs = [];
        try {
            fs.truncateSync(this.errorLogPath, 0);
        } catch (error) {
            serverLogger.error("Failed to clear error log file:", error);
        }
    }
    /**
   * Get error statistics
   */ getStats() {
        const stats = {
            total: this.errorLogs.length,
            byLevel: {},
            byOperation: {},
            recentErrors: this.errorLogs.slice(-10)
        };
        this.errorLogs.forEach((log)=>{
            // Count by level
            stats.byLevel[log.level] = (stats.byLevel[log.level] || 0) + 1;
            // Count by operation
            stats.byOperation[log.context.operation] = (stats.byOperation[log.context.operation] || 0) + 1;
        });
        return stats;
    }
}
// Singleton instance
let errorHandler = null;
export function getErrorHandler() {
    if (!errorHandler) {
        errorHandler = new ErrorHandler();
    }
    return errorHandler;
}
/**
 * Wrap an async function with error handling
 */ export function withErrorHandler(fn, context) {
    return async (...args)=>{
        try {
            return await fn(...args);
        } catch (error) {
            const handler = getErrorHandler();
            handler.logError(error, context);
            // Attempt recovery
            await handler.attemptRecovery(context.operation);
            throw error;
        }
    };
}
/**
 * Create a resilient operation that retries with exponential backoff
 */ export async function resilientOperation(operation, context, maxRetries = 3, baseDelay = 1000) {
    const handler = getErrorHandler();
    for(let attempt = 0; attempt < maxRetries; attempt++){
        try {
            return await operation();
        } catch (error) {
            handler.logError(error, {
                ...context,
                metadata: {
                    ...context.metadata,
                    attempt: attempt + 1,
                    maxRetries
                }
            });
            if (attempt === maxRetries - 1) {
                throw error;
            }
            // Exponential backoff
            const delay = baseDelay * Math.pow(2, attempt);
            await new Promise((resolve)=>setTimeout(resolve, delay));
        }
    }
    throw new Error("Should not reach here");
}

//# sourceMappingURL=errorHandler-standalone.js.map