"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const node_test_1 = __importDefault(require("node:test"));
const strict_1 = __importDefault(require("node:assert/strict"));
const schema_cache_js_1 = require("../schema-cache.js");
function makeFetcher(labels, rels, opts = {}) {
    let called = 0;
    let currentLabels = labels;
    let currentRels = rels;
    return {
        get calls() {
            return called;
        },
        async labels() {
            called++;
            if (opts.failOnce && called === 1)
                throw new Error("transient");
            return currentLabels;
        },
        async relationshipTypes() {
            return currentRels;
        },
    };
}
(0, node_test_1.default)("start() populates the snapshot and sets ready()", async () => {
    const fetcher = makeFetcher(["Conversation", "Message"], ["PART_OF"]);
    const emitted = [];
    const cache = new schema_cache_js_1.SchemaCache(fetcher, {
        refreshIntervalMs: 0,
        emit: (l) => emitted.push(l),
    });
    strict_1.default.equal(cache.ready(), false);
    await cache.start();
    strict_1.default.equal(cache.ready(), true);
    const snap = cache.snapshot();
    strict_1.default.ok(snap.labels.has("Conversation"));
    strict_1.default.ok(snap.labels.has("Message"));
    strict_1.default.ok(snap.relationshipTypes.has("PART_OF"));
    strict_1.default.ok(emitted.some((l) => l.includes("[schema-cache] refresh")));
    cache.stop();
});
(0, node_test_1.default)("start() with Neo4j unreachable leaves cache empty and not ready, but does not throw", async () => {
    const fetcher = {
        async labels() {
            throw new Error("ECONNREFUSED");
        },
        async relationshipTypes() {
            throw new Error("ECONNREFUSED");
        },
    };
    const emitted = [];
    const cache = new schema_cache_js_1.SchemaCache(fetcher, {
        refreshIntervalMs: 0,
        emit: (l) => emitted.push(l),
    });
    await cache.start();
    strict_1.default.equal(cache.ready(), false);
    strict_1.default.equal(cache.snapshot().labels.size, 0);
    strict_1.default.ok(emitted.some((l) => l.includes("[schema-cache]") && l.includes("failure")), "expected a failure log line");
    cache.stop();
});
(0, node_test_1.default)("refresh() picks up a newly-added relationship type", async () => {
    let rels = ["PART_OF"];
    const fetcher = {
        async labels() {
            return ["Conversation"];
        },
        async relationshipTypes() {
            return rels;
        },
    };
    const cache = new schema_cache_js_1.SchemaCache(fetcher, { refreshIntervalMs: 0 });
    await cache.start();
    strict_1.default.equal(cache.snapshot().relationshipTypes.has("MIGRATED_EDGE"), false);
    rels = ["PART_OF", "MIGRATED_EDGE"];
    await cache.refresh("interval");
    strict_1.default.ok(cache.snapshot().relationshipTypes.has("MIGRATED_EDGE"));
    cache.stop();
});
(0, node_test_1.default)("refresh() preserves last good cache on transient failure", async () => {
    let fail = false;
    const fetcher = {
        async labels() {
            if (fail)
                throw new Error("transient");
            return ["Conversation"];
        },
        async relationshipTypes() {
            if (fail)
                throw new Error("transient");
            return ["PART_OF"];
        },
    };
    const cache = new schema_cache_js_1.SchemaCache(fetcher, { refreshIntervalMs: 0 });
    await cache.start();
    strict_1.default.equal(cache.ready(), true);
    fail = true;
    const ok = await cache.refresh("interval");
    strict_1.default.equal(ok, false);
    strict_1.default.equal(cache.ready(), true, "should remain ready after a transient failure");
    strict_1.default.ok(cache.snapshot().labels.has("Conversation"));
    cache.stop();
});
(0, node_test_1.default)("maybeRebuildOnStaleMiss() triggers refresh when an unknown token has a near match", async () => {
    let rels = ["PART_OF"];
    const fetcher = {
        async labels() {
            return ["Conversation"];
        },
        async relationshipTypes() {
            return rels;
        },
    };
    const cache = new schema_cache_js_1.SchemaCache(fetcher, {
        refreshIntervalMs: 0,
        staleMissDebounceMs: 0,
    });
    await cache.start();
    rels = ["PART_OF", "PART_OFF"];
    const triggered = await cache.maybeRebuildOnStaleMiss([
        { token: "PART_OFF", kind: "relationship", nearest: ["PART_OF"], hint: "" },
    ]);
    strict_1.default.equal(triggered, true);
    strict_1.default.ok(cache.snapshot().relationshipTypes.has("PART_OFF"));
    cache.stop();
});
(0, node_test_1.default)("maybeRebuildOnStaleMiss() skips when no near match (likely typo, not migration)", async () => {
    const fetcher = makeFetcher(["Conversation"], ["PART_OF"]);
    const cache = new schema_cache_js_1.SchemaCache(fetcher, {
        refreshIntervalMs: 0,
        staleMissDebounceMs: 0,
    });
    await cache.start();
    const callsBefore = fetcher.calls;
    const triggered = await cache.maybeRebuildOnStaleMiss([
        { token: "COMPLETELY_DIFFERENT", kind: "relationship", nearest: ["PART_OF"], hint: "" },
    ]);
    strict_1.default.equal(triggered, false);
    strict_1.default.equal(fetcher.calls, callsBefore, "no extra fetches when edit distance is far");
    cache.stop();
});
(0, node_test_1.default)("maybeRebuildOnStaleMiss() debounces repeated triggers", async () => {
    const fetcher = makeFetcher(["Conversation"], ["PART_OF"]);
    const cache = new schema_cache_js_1.SchemaCache(fetcher, {
        refreshIntervalMs: 0,
        staleMissDebounceMs: 5000,
    });
    await cache.start();
    const callsBefore = fetcher.calls;
    const unknown = [
        { token: "PART_OFF", kind: "relationship", nearest: ["PART_OF"], hint: "" },
    ];
    await cache.maybeRebuildOnStaleMiss(unknown);
    const afterFirst = fetcher.calls;
    await cache.maybeRebuildOnStaleMiss(unknown);
    strict_1.default.equal(fetcher.calls, afterFirst, "second call within debounce should not refetch");
    strict_1.default.ok(afterFirst > callsBefore, "first call did refetch");
    cache.stop();
});
//# sourceMappingURL=schema-cache.test.js.map