/**
 * Virtual filesystem manager.
 *
 * Coordinates multiple virtual file handlers to provide a unified
 * interface for reading, writing, and listing files that may have
 * different physical representations.
 */
import { getLogger } from "../../../util/logger.js";
import { ApiFileHandler } from "./handlers/api-handler.js";
import { SkillFileHandler } from "./handlers/skill-handler.js";
/**
 * Manages virtual file handlers and routes operations to the appropriate handler.
 *
 * Usage:
 * ```typescript
 * const vfs = new VirtualFileSystem();
 * vfs.registerHandler(new ApiFileHandler());
 *
 * // Check if a path is virtual
 * if (vfs.isVirtualPath("apis/MyAPI.ts")) {
 *   const content = await vfs.read("apis/MyAPI.ts", options);
 * }
 * ```
 */
export class VirtualFileSystem {
    handlers = [];
    /**
     * Register a handler for a type of virtual file.
     *
     * @param handler - The handler to register
     */
    registerHandler(handler) {
        this.handlers.push(handler);
    }
    /**
     * Get all registered handlers.
     */
    getHandlers() {
        return this.handlers;
    }
    /**
     * Find the handler for a virtual path.
     *
     * @param virtualPath - The virtual path to look up
     * @returns The matching handler, or undefined if none match
     */
    getHandler(virtualPath) {
        return this.handlers.find((h) => h.matches(virtualPath));
    }
    /**
     * Find the handler for a physical path.
     *
     * @param physicalPath - The physical path to look up
     * @returns The matching handler, or undefined if none match
     */
    getHandlerForPhysical(physicalPath) {
        return this.handlers.find((h) => h.matchesPhysical(physicalPath));
    }
    /**
     * Check if a path is a virtual path managed by any handler.
     *
     * @param path - The path to check
     * @returns true if any handler manages this path
     */
    isVirtualPath(path) {
        const logger = getLogger();
        const handlerTypes = this.handlers.map((h) => h.type);
        logger.info(`[VirtualFileSystem.isVirtualPath] path="${path}", handlers=[${handlerTypes.join(", ")}]`);
        for (const handler of this.handlers) {
            const matches = handler.matches(path);
            logger.info(`[VirtualFileSystem.isVirtualPath] handler=${handler.type}, matches=${matches}`);
            if (matches) {
                return true;
            }
        }
        return false;
    }
    /**
     * Check if a path is a physical path that should be blocked from direct reads.
     *
     * Physical paths are the underlying files that make up virtual files
     * (e.g., apis/MyAPI/api.yaml, apis/MyAPI/step_1.js). These should not
     * be read directly; instead, the virtual path (apis/MyAPI.ts) should be used.
     *
     * @param path - The path to check
     * @returns true if this is a physical path that should be blocked
     */
    isPhysicalPath(path) {
        return this.handlers.some((h) => h.matchesPhysical(path));
    }
    /**
     * Get error message for attempting to read a physical path directly.
     *
     * @param physicalPath - The physical path that was attempted to be read
     * @returns Error message pointing to the virtual path
     */
    getBlockedReadError(physicalPath) {
        const virtualPath = this.toVirtualPath(physicalPath);
        return `Cannot read physical API file '${physicalPath}'. Read the virtual API file instead: ${virtualPath}`;
    }
    /**
     * Parse a virtual path to extract metadata.
     *
     * @param virtualPath - The virtual path to parse
     * @returns Parsed info or undefined if not a virtual path
     */
    parse(virtualPath) {
        const handler = this.getHandler(virtualPath);
        return handler?.parse(virtualPath);
    }
    /**
     * Convert a physical path to its virtual representation.
     *
     * @param physicalPath - The physical path to convert
     * @returns The virtual path, or the original path if not managed by any handler
     */
    toVirtualPath(physicalPath) {
        for (const handler of this.handlers) {
            const virtualPath = handler.toVirtualPath(physicalPath);
            if (virtualPath) {
                return virtualPath;
            }
        }
        return physicalPath;
    }
    /**
     * Convert a list of physical paths to virtual paths, deduplicating as needed.
     *
     * @param physicalPaths - The physical paths to convert
     * @returns Array of virtual paths (deduplicated)
     */
    toVirtualPaths(physicalPaths) {
        const virtualPaths = new Set();
        for (const physPath of physicalPaths) {
            virtualPaths.add(this.toVirtualPath(physPath));
        }
        return Array.from(virtualPaths);
    }
    /**
     * Read content from a virtual file.
     *
     * @param virtualPath - The virtual path to read
     * @param options - Read options
     * @returns The file content, or undefined if not found or not a virtual path
     */
    async read(virtualPath, options) {
        const handler = this.getHandler(virtualPath);
        if (!handler) {
            return undefined;
        }
        return await handler.read(virtualPath, options);
    }
    /**
     * Write content to a virtual file.
     *
     * @param virtualPath - The virtual path to write
     * @param content - The content to write
     * @param options - Write options
     * @throws Error if path is not managed by any handler
     */
    async write(virtualPath, content, options) {
        const handler = this.getHandler(virtualPath);
        if (!handler) {
            throw new Error(`No handler found for virtual path: ${virtualPath}`);
        }
        await handler.write(virtualPath, content, options);
    }
    /**
     * Delete a virtual file.
     *
     * @param virtualPath - The virtual path to delete
     * @param options - Delete options
     * @returns List of physical paths that were deleted
     * @throws Error if path is not managed by any handler
     */
    async delete(virtualPath, options) {
        const handler = this.getHandler(virtualPath);
        if (!handler) {
            throw new Error(`No handler found for virtual path: ${virtualPath}`);
        }
        return await handler.delete(virtualPath, options);
    }
}
/**
 * Create a VirtualFileSystem with the default handlers registered.
 *
 * @param options - Optional configuration including feature flags
 */
export function createDefaultVirtualFileSystem(options) {
    const logger = getLogger();
    const vfs = new VirtualFileSystem();
    vfs.registerHandler(new ApiFileHandler());
    logger.info(`[VirtualFileSystem] Registered ApiFileHandler`);
    // ApiFileHandler transforms YAML API files to virtual TS - only needed in YAML mode
    if (!options?.sdkApiEnabled) {
        vfs.registerHandler(new ApiFileHandler());
    }
    // Register SkillFileHandler when:
    // 1. knowledgeManager is provided (for on-demand knowledge/facts)
    // 2. OR useSystemSkills is enabled (for original skills feature)
    const hasKnowledgeManager = !!options?.knowledgeManager;
    const shouldRegisterSkillHandler = hasKnowledgeManager || options?.useSystemSkills;
    if (shouldRegisterSkillHandler) {
        logger.info(`[VirtualFileSystem] Registering SkillFileHandler (hasKnowledgeManager=${hasKnowledgeManager}, useSystemSkills=${options?.useSystemSkills})`);
        vfs.registerHandler(new SkillFileHandler(options?.knowledgeManager));
    }
    else {
        logger.info(`[VirtualFileSystem] Skipping SkillFileHandler (hasKnowledgeManager=${hasKnowledgeManager}, useSystemSkills=${options?.useSystemSkills})`);
    }
    const handlerTypes = vfs.getHandlers().map((h) => h.type);
    logger.info(`[VirtualFileSystem] Created with handlers: [${handlerTypes.join(", ")}]`);
    return vfs;
}
//# sourceMappingURL=virtual-file-system.js.map