/**
 * BaseElementManager - Abstract base class for all element managers
 *
 * Provides common CRUD operations for all element types using the
 * Template Method Pattern:
 * - Defines the skeleton of operations in base class
 * - Lets subclasses override specific steps without changing structure
 *
 * Subclasses: SkillManager, TemplateManager, AgentManager, MemoryManager
 *
 * SECURITY:
 * 1. CRITICAL: Uses FileLockManager for atomic read/write operations
 * 2. HIGH: Path validation and sanitization to prevent traversal attacks
 * 3. MEDIUM: Security event logging for audit trail
 * 4. MEDIUM: Input validation and sanitization throughout
 */
import { IElementManager } from '../../types/elements/IElementManager.js';
import { IElement, ElementValidationResult } from '../../types/elements/IElement.js';
import { ElementType } from '../../portfolio/types.js';
import { PortfolioManager } from '../../portfolio/PortfolioManager.js';
import { FileLockManager } from '../../security/fileLockManager.js';
import { LRUCache } from '../../cache/LRUCache.js';
import { ElementEventDispatcher, ElementEventPayload } from '../../events/ElementEventDispatcher.js';
import { FileWatchService } from '../../services/FileWatchService.js';
import { FileOperationsService } from '../../services/FileOperationsService.js';
import { ValidationRegistry } from '../../services/validation/ValidationRegistry.js';
import { type ElementValidator } from '../../services/validation/ElementValidator.js';
import type { IStorageLayer } from '../../storage/IStorageLayer.js';
import type { ElementIndexEntry } from '../../storage/types.js';
import type { CacheMemoryBudget } from '../../cache/CacheMemoryBudget.js';
import type { BackupService } from '../../services/BackupService.js';
export interface BaseElementManagerOptions {
    elementDirOverride?: string;
    eventDispatcher?: ElementEventDispatcher;
    elementCacheTTL?: number;
    pathCacheTTL?: number;
    enableFileWatcher?: boolean;
    autoReloadOnExternalChange?: boolean;
    fileWatchService?: FileWatchService;
    memoryBudget?: CacheMemoryBudget;
    backupService?: BackupService;
}
/**
 * Record of an element that failed to load (Issue #708).
 * Stored so callers can distinguish "file not found" from "file invalid".
 */
export interface InvalidElementRecord {
    /** Relative file path within the element directory. */
    filePath: string;
    /** Human-readable reason the element was rejected. */
    reason: string;
    /** ISO timestamp of last failed load attempt. */
    failedAt: string;
}
/**
 * Abstract base class implementing common element management operations
 * Subclasses must implement element-specific logic via abstract methods
 */
export declare abstract class BaseElementManager<T extends IElement> implements IElementManager<T> {
    protected portfolioManager: PortfolioManager;
    protected fileLockManager: FileLockManager;
    protected fileOperations: FileOperationsService;
    protected fileWatchService?: FileWatchService;
    protected elementDir: string;
    /**
     * Specialized validator for this element type
     * Obtained from ValidationRegistry during construction
     */
    protected validator: ElementValidator;
    protected elements: LRUCache<T>;
    private filePathToId;
    private readonly elementGenerations;
    private cacheGenerationCounter;
    private watcherCleanup?;
    private readonly eventDispatcher;
    private readonly autoReloadOnExternalChange;
    private readonly elementType;
    private readonly memoryBudget?;
    protected readonly backupService?: BackupService;
    /** Map plural ElementType enum values to singular ContentValidator context.
     *  Partial because not all element types have a content context (e.g., ensembles). */
    private static readonly ELEMENT_TYPE_TO_CONTEXT;
    protected readonly storageLayer: IStorageLayer;
    /**
     * Issue #708: Elements that exist on disk but failed validation during load.
     * Keyed by relative file path for deduplication.
     */
    private readonly invalidElements;
    /**
     * Tracks file paths whose load failure has already been logged at error level.
     * Repeated failures with the same reason are demoted to debug to avoid log flooding.
     * Cleared when the file changes on disk or loads successfully.
     */
    private readonly suppressedLoadPaths;
    /**
     * Returns true if the most recent load() failure for this path was suppressed
     * because it was a repeat of an already-logged error.
     * Subclasses can use this to avoid duplicate security event logging.
     *
     * @param filePath - Relative file path within the element directory
     * @returns Whether the error for this path is currently suppressed
     */
    protected isLoadErrorSuppressed(filePath: string): boolean;
    protected afterLoad?(element: T, filePath: string): Promise<void>;
    protected beforeSave?(element: T, filePath: string): Promise<void>;
    protected afterSave?(element: T, filePath: string): Promise<void>;
    protected findByIdentifier?(identifier: string): Promise<T | undefined>;
    protected canDelete?(element: T): Promise<{
        allowed: boolean;
        reason?: string;
    }>;
    /**
     * Create a backup before overwriting an existing file.
     * Subclasses can override to no-op (e.g. MemoryManager has its own backup system).
     */
    protected createBackupBeforeSave(absolutePath: string): Promise<void>;
    /**
     * Create a backup before deleting a file (moves file to backup dir).
     * Returns true if the original file was moved (caller should skip deleteFile).
     * Subclasses can override to no-op (e.g. MemoryManager has its own backup system).
     */
    protected createBackupBeforeDelete(absolutePath: string): Promise<boolean>;
    /**
     * Provides access to the event dispatcher for subclasses that need to emit custom events.
     *
     * BaseElementManager handles standard lifecycle events (load, save, delete) automatically.
     * Subclasses should use this getter only when they need to emit additional domain-specific
     * events that are not part of the standard CRUD lifecycle.
     *
     * @example
     * // PersonaManager emits activation/deactivation events
     * this.dispatcher.emit('element:activate', this.createEventPayload({...}));
     *
     * @returns The ElementEventDispatcher instance used by this manager
     */
    protected get dispatcher(): ElementEventDispatcher;
    private static readonly MAX_ELEMENT_CACHE_SIZE;
    private static readonly MAX_PATH_CACHE_SIZE;
    /**
     * Constructor - initializes common dependencies
     * @param elementType - The type of element this manager handles
     * @param portfolioManager - Portfolio manager for directory resolution
     * @param fileLockManager - File lock manager for atomic operations
     * @param options - Configuration options including fileWatchService
     * @param fileOperationsService - Service for file operations
     * @param validationRegistry - Registry for obtaining type-specific validators
     */
    constructor(elementType: ElementType, portfolioManager: PortfolioManager, fileLockManager: FileLockManager, options: BaseElementManagerOptions | undefined, fileOperationsService: FileOperationsService, validationRegistry: ValidationRegistry);
    /**
     * Factory method for creating the storage layer.
     * Default returns ElementStorageLayer for .md elements.
     * Subclasses (e.g. MemoryManager) can override to return a different implementation.
     */
    protected createStorageLayer(fileOperationsService: FileOperationsService): IStorageLayer;
    /**
     * Returns the singular human-readable label for this element type (e.g., "skill", "persona").
     * Used in filename generation ({name}-{label}.md) and display strings.
     * Must return the singular form — not the plural ElementType value.
     */
    protected abstract getElementLabel(): string;
    /**
     * Returns a capitalized version of the element label.
     */
    protected getElementLabelCapitalized(): string;
    /**
     * Load an element from file
     * TEMPLATE METHOD: Defines the algorithm, subclasses customize steps
     *
     * SECURITY FIXES (inherited from original managers):
     * - this.fileLockManager.atomicReadFile() prevents race conditions
     * - Path validation prevents traversal attacks
     * - Security event logging for audit trail
     */
    load(filePath: string): Promise<T>;
    /**
     * Issue #695: Pre-fill missing metadata fields with sensible defaults
     * before parseMetadata() runs. This implements the "tolerant reader" pattern
     * — strict on output, lenient on input for older/sparse frontmatter.
     *
     * Mutates `data` in place. Logs a warning for each defaulted field so
     * operators know which files need updating.
     */
    private migrateMetadataDefaults;
    /**
     * Issue #708: Returns elements that exist on disk but failed validation during load.
     * Callers can use this to report invalid elements instead of silently hiding them.
     */
    getInvalidElements(): InvalidElementRecord[];
    /**
     * Issue #708: Check if a specific file failed validation during load.
     * Used by get_element to distinguish "not found" from "invalid".
     */
    getInvalidElement(name: string): InvalidElementRecord | undefined;
    /**
     * Save an element to file
     * TEMPLATE METHOD: Common save logic with hooks for customization
     *
     * SECURITY FIXES:
     * - this.fileLockManager.atomicWriteFile() for atomic operations
     * - Path validation to prevent traversal attacks
     * - Security event logging
     */
    save(element: T, filePath: string): Promise<void>;
    /**
     * Validate serialized element content before writing to disk.
     * Fix #908: Mirrors the read-path validation from SecureYamlParser.parse()
     * to ensure write → read symmetry. Content that fails this check would also
     * fail to load, so rejecting it on write prevents permanently broken elements.
     */
    private validateSerializedContent;
    /**
     * List all available elements
     * SECURITY: Uses PortfolioManager.listElements() which filters test elements
     */
    list(): Promise<T[]>;
    /**
     * List lightweight metadata summaries without loading full elements.
     * Useful when only names/descriptions/tags are needed.
     */
    listSummaries(): Promise<ElementIndexEntry[]>;
    /**
     * Find an element by predicate
     */
    find(predicate: (element: T) => boolean): Promise<T | undefined>;
    /**
     * Find multiple elements by predicate
     */
    findMany(predicate: (element: T) => boolean): Promise<T[]>;
    /**
     * Find an element by name or ID without loading all elements
     *
     * Issue #24 (LOW PRIORITY): Performance optimization for activation flow
     *
     * This method provides an optimized lookup that tries cache first, then
     * attempts direct file access before falling back to full list() scan.
     * This is significantly faster than list() for large portfolios.
     *
     * PERFORMANCE IMPROVEMENTS:
     * 1. Cache lookup - O(1) if element was previously loaded
     * 2. Direct file access - O(1) for name-based lookups
     * 3. Full scan fallback - O(n) only if above methods fail
     *
     * @param identifier - Element name or ID to search for
     * @returns Element if found, undefined otherwise
     */
    findByName(identifier: string): Promise<T | undefined>;
    /**
     * Helper: Search cache for element by name or ID
     * @private
     */
    private findInCache;
    /**
     * Helper: Try loading element directly by constructing expected filename
     * @private
     */
    private tryDirectLoad;
    /**
     * Validate an element
     * Delegates to element's own validate method
     *
     * @returns Validation result with both 'valid' and 'isValid' properties.
     *          'isValid' is deprecated - use 'valid' for new code.
     */
    validate(element: T): ElementValidationResult;
    /**
     * Delete an element
     * SECURITY: Path validation to prevent deletion outside directory
     * CACHE FIX: Uses filepath-based cache removal to prevent stale entries
     */
    delete(filePath: string): Promise<void>;
    /**
     * Check if an element exists
     */
    exists(filePath: string): Promise<boolean>;
    /**
     * Validate a file path
     */
    validatePath(filePath: string): boolean;
    /**
     * Get the element type
     */
    getElementType(): ElementType;
    /**
     * Resolves a file path to its absolute form for cache consistency
     * Ensures consistent path handling across relative/absolute paths
     */
    protected resolveAbsolutePath(filePath: string): string;
    private normalizeAndValidatePath;
    private getCachedElementByAbsolutePath;
    /**
     * Protected cache lookup by absolute path.
     * Allows subclasses with custom load() overrides (e.g. MemoryManager)
     * to check the LRU cache before re-reading from disk.
     */
    protected getCachedByAbsolutePath(absolutePath: string): T | undefined;
    private loadElementSnapshot;
    /**
     * Creates a standardized event payload for element lifecycle events.
     *
     * This helper is available to subclasses to ensure consistent event payload
     * structure when emitting custom events via the dispatcher getter.
     *
     * @param params - Event parameters including correlation ID, element, file path, and optional error
     * @returns Fully-formed ElementEventPayload ready for emission
     */
    protected createEventPayload(params: {
        correlationId: string;
        filePath?: string;
        element?: T;
        error?: unknown;
    }): ElementEventPayload;
    private handleExternalChange;
    /**
     * Adds an element to both caches (bidirectional mapping)
     * @param element - Element to cache
     * @param filePath - File path (relative or absolute)
     */
    protected cacheElement(element: T, filePath: string): void;
    /**
     * Force a fresh disk scan and evict any modified/removed entries from the
     * in-memory LRU cache. Call before findByName() when freshness is critical
     * (e.g. on ensemble activation) to pick up external file changes that
     * occurred since the last scan, even if the scan cooldown is still active.
     *
     * Unlike list(), this does not load all elements — it only evicts stale ones.
     * Fixes #1895 (ensemble activation serving stale cached element list).
     */
    protected scanAndEvict(): Promise<void>;
    /**
     * Removes an element from both caches by file path
     * This is the preferred method for deletion to avoid stale cache entries
     * @param filePath - File path (relative or absolute)
     */
    protected uncacheByPath(filePath: string): void;
    /**
     * Clear all cached elements
     */
    clearCache(): void;
    /**
     * Get cache statistics for debugging
     * @returns Object with cache size metrics
     */
    protected getCacheStats(): {
        elementCount: number;
        pathMappings: number;
    };
    /**
     * Expose internal LRU cache instances for metrics collection.
     */
    getMetricsCaches(): Array<{
        name: string;
        instance: LRUCache<unknown>;
    }>;
    /**
     * Dispose of resources and cleanup
     * Subclasses should override to add their own cleanup logic
     */
    dispose(): void;
    /**
     * Normalize a name to kebab-case for consistent filename formatting.
     *
     * This method provides unified filename normalization across all element managers,
     * ensuring consistent naming regardless of the input format (CamelCase, spaces,
     * underscores, mixed case, etc.).
     *
     * Transformations applied (in order):
     * 1. Insert hyphens between camelCase boundaries (MyName -> My-Name)
     * 2. Replace spaces and underscores with hyphens
     * 3. Convert to lowercase
     * 4. Strip invalid characters (keep only a-z, 0-9, -)
     * 5. Collapse multiple consecutive hyphens
     * 6. Trim leading/trailing hyphens
     *
     * @example
     * normalizeFilename("CRUDV-Agent-Delta") // "crudv-agent-delta"
     * normalizeFilename("Creative Writer")   // "creative-writer"
     * normalizeFilename("CamelCaseName")     // "camel-case-name"
     * normalizeFilename("my_skill_name")     // "my-skill-name"
     * normalizeFilename("Special@Chars!")    // "special-chars"
     * normalizeFilename("--leading-and-trailing--") // "leading-and-trailing"
     *
     * @param name - The element name to normalize
     * @returns Normalized kebab-case filename (without extension)
     */
    protected normalizeFilename(name: string): string;
    /**
     * Get the standardized filename for an element.
     *
     * Normalizes the element name (handling CamelCase, spaces, underscores, etc.)
     * and appends the file extension. The directory structure (personas/, skills/, etc.)
     * already provides type context, so the type is NOT included in the filename.
     *
     * @param name - The element name to convert to a filename
     * @returns The standardized filename (e.g., "code-review.md")
     *
     * @example
     * getElementFilename("Code Review")         // → "code-review.md"
     * getElementFilename("Debug Detective")     // → "debug-detective.md"
     * getElementFilename("BugReport")           // → "bug-report.md" (CamelCase split)
     * getElementFilename("fix-persona-helper")  // → "fix-persona-helper.md" (no mangling)
     */
    protected getElementFilename(name: string): string;
    /**
     * Parse and validate metadata from frontmatter
     * Subclasses implement element-specific validation logic
     *
     * @param data - Raw metadata from YAML frontmatter
     * @returns Validated and typed metadata
     */
    protected abstract parseMetadata(data: any): Promise<T['metadata']>;
    /**
     * @deprecated Use ElementValidator via ValidationRegistry instead.
     * Will be removed in next major version.
     */
    validateMetadata(metadata: any, _strict?: boolean): Promise<import('../../utils/validation/FieldValidator.js').ValidationError[]>;
    /**
     * Create an element instance from metadata and content
     * Subclasses implement element-specific construction
     *
     * @param metadata - Validated metadata
     * @param content - Element content (instructions, template, etc.)
     * @returns New element instance
     */
    protected abstract createElement(metadata: T['metadata'], content: string): T;
    /**
     * Serialize an element to file content
     * Subclasses can customize serialization format
     *
     * @param element - Element to serialize
     * @returns File content (usually markdown with frontmatter)
     */
    protected abstract serializeElement(element: T): Promise<string>;
    /**
     * Get the file extension for this element type
     * Most elements use .md, but subclasses can override
     */
    abstract getFileExtension(): string;
    /**
     * Import an element from external format
     * Subclasses implement format-specific import logic
     */
    abstract importElement(data: string, format?: 'json' | 'yaml' | 'markdown'): Promise<T>;
    /**
     * Export an element to external format
     * Subclasses implement format-specific export logic
     */
    abstract exportElement(element: T, format?: 'json' | 'yaml' | 'markdown'): Promise<string>;
}
//# sourceMappingURL=BaseElementManager.d.ts.map