"use strict";
Object.defineProperty(exports, "__esModule", {
    value: true
});
Object.defineProperty(exports, "KVDocumentStore", {
    enumerable: true,
    get: function() {
        return KVDocumentStore;
    }
});
const _lodash = /*#__PURE__*/ _interop_require_default(require("lodash"));
const _Node = require("../../Node.js");
const _constants = require("../constants.js");
const _types = require("./types.js");
const _utils = require("./utils.js");
function _interop_require_default(obj) {
    return obj && obj.__esModule ? obj : {
        default: obj
    };
}
class KVDocumentStore extends _types.BaseDocumentStore {
    kvstore;
    nodeCollection;
    refDocCollection;
    metadataCollection;
    constructor(kvstore, namespace = _constants.DEFAULT_NAMESPACE){
        super();
        this.kvstore = kvstore;
        this.nodeCollection = `${namespace}/data`;
        this.refDocCollection = `${namespace}/ref_doc_info`;
        this.metadataCollection = `${namespace}/metadata`;
    }
    async docs() {
        const jsonDict = await this.kvstore.getAll(this.nodeCollection);
        const docs = {};
        for(const key in jsonDict){
            const value = jsonDict[key];
            if ((0, _utils.isValidDocJson)(value)) {
                docs[key] = (0, _utils.jsonToDoc)(value);
            } else {
                console.warn(`Invalid JSON for docId ${key}`);
            }
        }
        return docs;
    }
    async addDocuments(docs, allowUpdate = true) {
        for(let idx = 0; idx < docs.length; idx++){
            const doc = docs[idx];
            if (doc.id_ === null) {
                throw new Error("doc_id not set");
            }
            if (!allowUpdate && await this.documentExists(doc.id_)) {
                throw new Error(`doc_id ${doc.id_} already exists. Set allow_update to True to overwrite.`);
            }
            const nodeKey = doc.id_;
            const data = (0, _utils.docToJson)(doc);
            await this.kvstore.put(nodeKey, data, this.nodeCollection);
            const metadata = {
                docHash: doc.hash
            };
            if (doc.type === _Node.ObjectType.TEXT && doc.sourceNode !== undefined) {
                const refDocInfo = await this.getRefDocInfo(doc.sourceNode.nodeId) || {
                    nodeIds: [],
                    extraInfo: {}
                };
                refDocInfo.nodeIds.push(doc.id_);
                if (_lodash.default.isEmpty(refDocInfo.extraInfo)) {
                    refDocInfo.extraInfo = {};
                }
                await this.kvstore.put(doc.sourceNode.nodeId, refDocInfo, this.refDocCollection);
                metadata.refDocId = doc.sourceNode.nodeId;
            }
            await this.kvstore.put(nodeKey, metadata, this.metadataCollection);
        }
    }
    async getDocument(docId, raiseError = true) {
        const json = await this.kvstore.get(docId, this.nodeCollection);
        if (_lodash.default.isNil(json)) {
            if (raiseError) {
                throw new Error(`docId ${docId} not found.`);
            } else {
                return;
            }
        }
        if (!(0, _utils.isValidDocJson)(json)) {
            throw new Error(`Invalid JSON for docId ${docId}`);
        }
        return (0, _utils.jsonToDoc)(json);
    }
    async getRefDocInfo(refDocId) {
        const refDocInfo = await this.kvstore.get(refDocId, this.refDocCollection);
        return refDocInfo ? _lodash.default.clone(refDocInfo) : undefined;
    }
    async getAllRefDocInfo() {
        const refDocInfos = await this.kvstore.getAll(this.refDocCollection);
        if (_lodash.default.isNil(refDocInfos)) {
            return;
        }
        return refDocInfos;
    }
    async refDocExists(refDocId) {
        return !_lodash.default.isNil(await this.getRefDocInfo(refDocId));
    }
    async documentExists(docId) {
        return !_lodash.default.isNil(await this.kvstore.get(docId, this.nodeCollection));
    }
    async removeRefDocNode(docId) {
        const metadata = await this.kvstore.get(docId, this.metadataCollection);
        if (metadata === null) {
            return;
        }
        const refDocId = metadata.refDocId;
        if (_lodash.default.isNil(refDocId)) {
            return;
        }
        const refDocInfo = await this.kvstore.get(refDocId, this.refDocCollection);
        if (!_lodash.default.isNil(refDocInfo)) {
            !_lodash.default.pull(refDocInfo.nodeIds, docId);
            if (refDocInfo.nodeIds.length > 0) {
                await this.kvstore.put(refDocId, refDocInfo, this.refDocCollection);
            }
            await this.kvstore.delete(refDocId, this.metadataCollection);
        }
    }
    async deleteDocument(docId, raiseError = true, removeRefDocNode = true) {
        if (removeRefDocNode) {
            await this.removeRefDocNode(docId);
        }
        const deleteSuccess = await this.kvstore.delete(docId, this.nodeCollection);
        await this.kvstore.delete(docId, this.metadataCollection);
        if (!deleteSuccess && raiseError) {
            throw new Error(`doc_id ${docId} not found.`);
        }
    }
    async deleteRefDoc(refDocId, raiseError = true) {
        const refDocInfo = await this.getRefDocInfo(refDocId);
        if (_lodash.default.isNil(refDocInfo)) {
            if (raiseError) {
                throw new Error(`ref_doc_id ${refDocId} not found.`);
            } else {
                return;
            }
        }
        for (const docId of refDocInfo.nodeIds){
            await this.deleteDocument(docId, false, false);
        }
        await this.kvstore.delete(refDocId, this.metadataCollection);
        await this.kvstore.delete(refDocId, this.refDocCollection);
    }
    async setDocumentHash(docId, docHash) {
        const metadata = {
            docHash: docHash
        };
        await this.kvstore.put(docId, metadata, this.metadataCollection);
    }
    async getDocumentHash(docId) {
        const metadata = await this.kvstore.get(docId, this.metadataCollection);
        return _lodash.default.get(metadata, "docHash");
    }
    async getAllDocumentHashes() {
        const hashes = {};
        const metadataDocs = await this.kvstore.getAll(this.metadataCollection);
        for(const docId in metadataDocs){
            const hash = await this.getDocumentHash(docId);
            if (hash) {
                hashes[hash] = docId;
            }
        }
        return hashes;
    }
}
