/**
 * MCP Server Error Handling
 *
 * FAIL FAST: All errors throw immediately with descriptive context.
 * NO graceful degradation, NO fallbacks.
 *
 * @module server/errors
 */
// ═══════════════════════════════════════════════════════════════════════════════
// ERROR NAME TO CATEGORY MAPPING
// ═══════════════════════════════════════════════════════════════════════════════
/**
 * Valid ErrorCategory values for runtime checking (OCRError has its own category field)
 */
const VALID_CATEGORIES = new Set([
    'VALIDATION_ERROR',
    'DATABASE_NOT_FOUND',
    'DATABASE_NOT_SELECTED',
    'DATABASE_ALREADY_EXISTS',
    'DOCUMENT_NOT_FOUND',
    'PROVENANCE_NOT_FOUND',
    'PROVENANCE_CHAIN_BROKEN',
    'INTEGRITY_VERIFICATION_FAILED',
    'OCR_TIMEOUT',
    'GPU_NOT_AVAILABLE',
    'GPU_OUT_OF_MEMORY',
    'EMBEDDING_FAILED',
    'EMBEDDING_MODEL_ERROR',
    'VLM_API_ERROR',
    'IMAGE_EXTRACTION_FAILED',
    'CLUSTERING_ERROR',
    'PATH_NOT_FOUND',
    'PATH_NOT_DIRECTORY',
    'PERMISSION_DENIED',
    'CONFIGURATION_ERROR',
    'INTERNAL_ERROR',
]);
/**
 * Check if a string is a valid ErrorCategory
 */
function isValidCategory(value) {
    return VALID_CATEGORIES.has(value);
}
/**
 * Map custom error class names to MCPError categories.
 * CS-ERR-001: Every custom error gets its appropriate category so clients
 * can programmatically distinguish GPU failures from DB locks from timeouts.
 *
 * OCRError and its subclasses are handled specially in fromUnknown() because
 * they carry their own .category field with more specific information
 * (e.g., OCR_TIMEOUT, OCR_FILE_ERROR, OCR_GPU_ERROR).
 */
const ERROR_NAME_TO_CATEGORY = {
    // Validation
    ValidationError: 'VALIDATION_ERROR',
    // Database / Storage
    DatabaseError: 'DATABASE_NOT_FOUND',
    VectorError: 'INTERNAL_ERROR',
    MigrationError: 'INTERNAL_ERROR',
    // OCR (default category; subclasses use their own .category field)
    OCRError: 'OCR_TIMEOUT',
    OCRTimeoutError: 'OCR_TIMEOUT',
    OCRFileError: 'OCR_TIMEOUT',
    OCRModelError: 'OCR_TIMEOUT',
    OCRGPUError: 'OCR_TIMEOUT',
    // Embedding / GPU
    EmbeddingError: 'EMBEDDING_FAILED',
    // Provenance
    ProvenanceError: 'PROVENANCE_CHAIN_BROKEN',
    VerifierError: 'INTEGRITY_VERIFICATION_FAILED',
    ExporterError: 'INTERNAL_ERROR',
    // VLM (local Chandra)
    ChandraError: 'VLM_API_ERROR',
    // Clustering
    ClusteringError: 'CLUSTERING_ERROR',
};
/**
 * OCR error class names that carry their own `.category` field.
 * Used in fromUnknown() to prefer the error's category over the default mapping.
 */
const OCR_ERROR_NAMES = new Set([
    'OCRError',
    'OCRTimeoutError',
    'OCRFileError',
    'OCRModelError',
    'OCRGPUError',
]);
// ═══════════════════════════════════════════════════════════════════════════════
// MCP ERROR CLASS
// ═══════════════════════════════════════════════════════════════════════════════
/**
 * MCPError - Structured error class for all MCP tool failures
 *
 * FAIL FAST: Thrown immediately when any error condition is detected.
 * Provides category, message, and optional details for debugging.
 */
export class MCPError extends Error {
    category;
    details;
    constructor(category, message, details) {
        super(message);
        this.name = 'MCPError';
        this.category = category;
        this.details = details;
        // Preserve stack trace in V8 environments
        if (Error.captureStackTrace) {
            Error.captureStackTrace(this, MCPError);
        }
    }
    /**
     * Create error from unknown caught value
     * FAIL FAST: Always produces a typed error
     */
    static fromUnknown(error, defaultCategory = 'INTERNAL_ERROR') {
        if (error instanceof MCPError) {
            return error;
        }
        if (error instanceof Error) {
            // Map custom error class names to their appropriate MCPError categories.
            // CS-ERR-001: Every custom error class maps to a specific category so
            // clients can programmatically distinguish failure modes.
            const category = ERROR_NAME_TO_CATEGORY[error.name] ?? defaultCategory;
            // For OCRError subclasses, preserve the more specific category from the error itself
            const ocrCategory = error.category;
            const resolvedCategory = OCR_ERROR_NAMES.has(error.name) && ocrCategory && isValidCategory(ocrCategory)
                ? ocrCategory
                : category;
            // Preserve diagnostic properties from custom error classes (VectorError, EmbeddingError, etc.)
            const customDetails = error.details;
            const customCode = error.code;
            // L-5: Log stack trace to stderr for debugging, but do NOT include in client-facing details
            if (error.stack) {
                console.error(`[MCPError] ${error.name}: ${error.message}\n${error.stack}`);
            }
            return new MCPError(resolvedCategory, error.message, {
                originalName: error.name,
                ...(customCode && { errorCode: customCode }),
                ...(customDetails && { errorDetails: customDetails }),
            });
        }
        return new MCPError(defaultCategory, String(error), {
            originalValue: error,
        });
    }
    /**
     * Convert to JSON for logging/serialization
     */
    toJSON() {
        return {
            name: this.name,
            category: this.category,
            message: this.message,
            details: this.details,
        };
    }
}
/**
 * Recovery hints for every error category.
 * Agents use these to determine the next action after a failure.
 */
const RECOVERY_HINTS = {
    VALIDATION_ERROR: { tool: 'ocr_guide', hint: 'Check parameter types and required fields' },
    DATABASE_NOT_FOUND: { tool: 'ocr_db_list', hint: 'Use ocr_db_list to see available databases' },
    DATABASE_NOT_SELECTED: {
        tool: 'ocr_db_select',
        hint: 'Use ocr_db_list to find database names, then ocr_db_select',
    },
    DATABASE_ALREADY_EXISTS: { tool: 'ocr_db_list', hint: 'Choose a unique database name' },
    DOCUMENT_NOT_FOUND: {
        tool: 'ocr_document_list',
        hint: 'Use ocr_document_list to browse available documents',
    },
    PROVENANCE_NOT_FOUND: {
        tool: 'ocr_provenance_get',
        hint: 'Verify the item_id exists using ocr_document_get first',
    },
    PROVENANCE_CHAIN_BROKEN: {
        tool: 'ocr_provenance_verify',
        hint: 'Re-ingest the document to rebuild provenance chain',
    },
    INTEGRITY_VERIFICATION_FAILED: {
        tool: 'ocr_provenance_verify',
        hint: 'Compare content_hash against stored hash; re-ingest if tampered',
    },
    OCR_TIMEOUT: { tool: 'ocr_process_pending', hint: 'Retry with smaller documents or fewer pages' },
    GPU_NOT_AVAILABLE: {
        tool: 'ocr_health_check',
        hint: 'Check CUDA GPU availability; CUDA is required with no CPU/MPS fallback',
    },
    GPU_OUT_OF_MEMORY: {
        tool: 'ocr_config_set',
        hint: 'Reduce embedding_batch_size via ocr_config_set',
    },
    EMBEDDING_FAILED: {
        tool: 'ocr_health_check',
        hint: 'Check Python embedding worker and GPU memory',
    },
    EMBEDDING_MODEL_ERROR: {
        tool: 'ocr_health_check',
        hint: 'Verify nomic-embed-text model is downloaded',
    },
    VLM_API_ERROR: { tool: 'ocr_vlm_status', hint: 'Check Chandra VLM worker and GPU availability' },
    IMAGE_EXTRACTION_FAILED: { tool: 'ocr_health_check', hint: 'Check PyMuPDF/Pillow installation' },
    CLUSTERING_ERROR: {
        tool: 'ocr_health_check',
        hint: 'Check Python clustering worker (scikit-learn)',
    },
    PATH_NOT_FOUND: { tool: 'ocr_guide', hint: 'Verify the file path exists on the filesystem' },
    PATH_NOT_DIRECTORY: { tool: 'ocr_guide', hint: 'Provide a directory path, not a file path' },
    PERMISSION_DENIED: { tool: 'ocr_guide', hint: 'Check filesystem permissions on the target path' },
    CONFIGURATION_ERROR: {
        tool: 'ocr_health_check',
        hint: 'Check environment variable configuration and GPU availability. In Docker, pass via -e flags.',
    },
    INTERNAL_ERROR: { tool: 'ocr_health_check', hint: 'Run ocr_health_check for diagnostics' },
};
/**
 * Get recovery hint for an error category.
 * Exported for testing and direct use.
 */
export function getRecoveryHint(category) {
    return RECOVERY_HINTS[category];
}
// ═══════════════════════════════════════════════════════════════════════════════
// ERROR RESPONSE FORMATTING
// ═══════════════════════════════════════════════════════════════════════════════
/**
 * Format MCPError for tool response
 * ALWAYS includes category, message, recovery hint, and optional details.
 * The recovery field tells AI agents which tool to call next and how to fix the issue.
 */
export function formatErrorResponse(error) {
    return {
        success: false,
        error: {
            category: error.category,
            message: error.message,
            recovery: RECOVERY_HINTS[error.category],
            details: error.details,
        },
    };
}
// ═══════════════════════════════════════════════════════════════════════════════
// ERROR FACTORY FUNCTIONS
// ═══════════════════════════════════════════════════════════════════════════════
/**
 * Create validation error
 */
export function validationError(message, details) {
    return new MCPError('VALIDATION_ERROR', message, details);
}
/**
 * Create database not selected error
 */
export function databaseNotSelectedError() {
    return new MCPError('DATABASE_NOT_SELECTED', 'No database selected. Use ocr_db_list to see available databases, then ocr_db_select to choose one.');
}
/**
 * Create database not found error
 */
export function databaseNotFoundError(name, storagePath) {
    return new MCPError('DATABASE_NOT_FOUND', `Database "${name}" not found`, {
        databaseName: name,
        storagePath,
    });
}
/**
 * Create database already exists error
 */
export function databaseAlreadyExistsError(name) {
    return new MCPError('DATABASE_ALREADY_EXISTS', `Database "${name}" already exists`, {
        databaseName: name,
    });
}
/**
 * Create document not found error
 */
export function documentNotFoundError(documentId) {
    return new MCPError('DOCUMENT_NOT_FOUND', `Document not found: ${documentId}. Use ocr_document_list to browse available documents.`, {
        documentId,
    });
}
/**
 * Create provenance not found error
 */
export function provenanceNotFoundError(itemId) {
    return new MCPError('PROVENANCE_NOT_FOUND', `Provenance for "${itemId}" not found`, {
        itemId,
    });
}
/**
 * Create path not found error
 */
export function pathNotFoundError(path) {
    return new MCPError('PATH_NOT_FOUND', `Path does not exist: ${path}`, {
        path,
    });
}
/**
 * Create path not directory error
 */
export function pathNotDirectoryError(path) {
    return new MCPError('PATH_NOT_DIRECTORY', `Path is not a directory: ${path}`, {
        path,
    });
}
//# sourceMappingURL=errors.js.map