import { TextNode } from "../Node.js";
import { extractText } from "../llm/utils.js";
// Assuming that necessary interfaces and classes (like OT, TextNode, BaseNode, etc.) are defined elsewhere
// Import statements (e.g., for TextNode, BaseNode) should be added based on your project's structure
export class BaseObjectNodeMapping {
    // Concrete methods can be defined as usual
    validateObject(obj) {}
    // Implementing the add object logic
    addObj(obj) {
        this.validateObject(obj);
        this._addObj(obj);
    }
    // Implementing toNodes method
    toNodes(objs) {
        return objs.map((obj)=>this.toNode(obj));
    }
    // Implementing fromNode method
    fromNode(node) {
        const obj = this._fromNode(node);
        this.validateObject(obj);
        return obj;
    }
}
export class ObjectRetriever {
    _retriever;
    _objectNodeMapping;
    constructor(retriever, objectNodeMapping){
        this._retriever = retriever;
        this._objectNodeMapping = objectNodeMapping;
    }
    // In TypeScript, getters are defined like this.
    get retriever() {
        return this._retriever;
    }
    // Translating the retrieve method
    async retrieve(strOrQueryBundle) {
        const nodes = await this.retriever.retrieve({
            query: extractText(strOrQueryBundle)
        });
        const objs = nodes.map((n)=>this._objectNodeMapping.fromNode(n.node));
        return objs;
    }
}
const convertToolToNode = (tool)=>{
    const nodeText = `
    Tool name: ${tool.metadata.name}
    Tool description: ${tool.metadata.description}
  `;
    return new TextNode({
        text: nodeText,
        metadata: {
            name: tool.metadata.name
        },
        excludedEmbedMetadataKeys: [
            "name"
        ],
        excludedLlmMetadataKeys: [
            "name"
        ]
    });
};
export class SimpleToolNodeMapping extends BaseObjectNodeMapping {
    _tools;
    constructor(objs = []){
        super();
        this._tools = {};
        for (const tool of objs){
            this._tools[tool.metadata.name] = tool;
        }
    }
    objNodeMapping() {
        return this._tools;
    }
    toNode(tool) {
        return convertToolToNode(tool);
    }
    _addObj(tool) {
        this._tools[tool.metadata.name] = tool;
    }
    _fromNode(node) {
        if (!node.metadata) {
            throw new Error("Metadata must be set");
        }
        return this._tools[node.metadata.name];
    }
    persist(persistDir, objNodeMappingFilename) {
    // Implement the persist method
    }
    toNodes(objs) {
        return objs.map((obj)=>this.toNode(obj));
    }
    addObj(obj) {
        this._addObj(obj);
    }
    fromNode(node) {
        return this._fromNode(node);
    }
    static fromObjects(objs, ...args) {
        return new SimpleToolNodeMapping(objs);
    }
    fromObjects(objs, ...args) {
        return new SimpleToolNodeMapping(objs);
    }
}
export class ObjectIndex {
    _index;
    _objectNodeMapping;
    constructor(index, objectNodeMapping){
        this._index = index;
        this._objectNodeMapping = objectNodeMapping;
    }
    static async fromObjects(objects, objectMapping, // TODO: fix any (bundling issue)
    indexCls, indexKwargs) {
        if (objectMapping === null) {
            objectMapping = SimpleToolNodeMapping.fromObjects(objects, {});
        }
        const nodes = objectMapping.toNodes(objects);
        const index = await indexCls.init({
            nodes,
            ...indexKwargs
        });
        return new ObjectIndex(index, objectMapping);
    }
    async insertObject(obj) {
        this._objectNodeMapping.addObj(obj);
        const node = this._objectNodeMapping.toNode(obj);
        await this._index.insertNodes([
            node
        ]);
    }
    get tools() {
        return this._objectNodeMapping.objNodeMapping();
    }
    async asRetriever(kwargs) {
        return new ObjectRetriever(this._index.asRetriever(kwargs), this._objectNodeMapping);
    }
    asNodeRetriever(kwargs) {
        return this._index.asRetriever(kwargs);
    }
}
