import { expect, test } from "vitest";
import { openLix } from "../../lix/open-lix.js";
import { generateCommit } from "./generate-commit.js";
import { getTimestamp } from "../../engine/functions/timestamp.js";
import { uuidV7 } from "../../engine/functions/uuid-v7.js";
function groupBySchema(rows) {
    const m = new Map();
    for (const r of rows) {
        (m.get(r.schema_key) || m.set(r.schema_key, []).get(r.schema_key)).push(r);
    }
    return m;
}
test("scenario 1: 1 key_value on active (with author)", async () => {
    const lix = await openLix({
        keyValues: [
            {
                key: "lix_deterministic_mode",
                value: { enabled: true },
                lixcol_version_id: "global",
            },
        ],
    });
    const now = await getTimestamp({ lix });
    const preIds = [
        await uuidV7({ lix }),
        await uuidV7({ lix }),
        await uuidV7({ lix }),
    ];
    // domain change on active version
    const chgId = "chg_active";
    const userChange = {
        id: chgId,
        entity_id: "kv_active",
        schema_key: "lix_key_value",
        schema_version: "1.0",
        file_id: "lix",
        plugin_key: "lix_sdk",
        snapshot_content: JSON.stringify({ key: "a", value: "1" }),
        created_at: now,
        version_id: "version-main",
    };
    const res = generateCommit({
        timestamp: now,
        activeAccounts: ["acct-1"],
        changes: [userChange],
        versions: new Map([
            [
                "version-main",
                {
                    parent_commit_ids: ["P_active"],
                    snapshot: {
                        id: "version-main",
                        name: "main",
                        commit_id: "ignore_active",
                        working_commit_id: "work-main",
                        inherits_from_version_id: "global",
                        hidden: false,
                    },
                },
            ],
            [
                "global",
                {
                    parent_commit_ids: ["P_global"],
                    snapshot: {
                        id: "global",
                        name: "global",
                        commit_id: "ignore_global",
                        working_commit_id: "work-global",
                        inherits_from_version_id: null,
                        hidden: true,
                    },
                },
            ],
        ]),
        generateUuid: () => preIds.shift() || "uuid_fallback",
    });
    const bySchema = groupBySchema(res.changes);
    // Domain + Metadata rows (no commit_edge change rows)
    expect(bySchema.get("lix_key_value")?.length ?? 0).toBe(1);
    // No author change rows (authors live on commit)
    expect(bySchema.get("lix_change_author")?.length ?? 0).toBe(0);
    expect(bySchema.get("lix_commit")?.length ?? 0).toBe(1);
    // change_set is synthesized in cache from commit.snapshot.change_set_id (no change row)
    expect(bySchema.get("lix_change_set")?.length ?? 0).toBe(0);
    expect(bySchema.get("lix_commit_edge")?.length ?? 0).toBe(0);
    // Version pointers are now committed via lix_version_tip (meta ledger)
    expect(bySchema.get("lix_version_tip")?.length ?? 0).toBe(1);
    // No descriptor writes during commit; descriptor is domain-only bootstrap/update
    expect(bySchema.get("lix_version_descriptor")?.length ?? 0).toBe(0);
    // Change set elements are derived in Step 1 (no change rows)
    expect(bySchema.get("lix_change_set_element")?.length ?? 0).toBe(0);
    const commits = (bySchema.get("lix_commit") || []).map((c) => JSON.parse(c.snapshot_content));
    // Step 1: commit snapshot includes change_ids for derivation
    expect(typeof commits[0].change_set_id).toBe("string");
    // version_id/author_account_ids are no longer on commit snapshots
    expect(commits[0].version_id).toBeUndefined();
    expect(commits[0].meta_change_ids?.length ?? 0).toBe(1);
    // Commit-level authors
    expect(commits[0].author_account_ids).toEqual(["acct-1"]);
    expect(commits[0].parent_commit_ids).toEqual(["P_active"]);
    // Materialized state (cache)
    // Synthesized: domain-only CSE; domain rows are included for the commit's version
    const bySchemaMat = groupBySchema(res.materializedState ?? []);
    expect(bySchemaMat.get("lix_key_value")?.length ?? 0).toBe(1);
    expect(bySchemaMat.get("lix_change_author")?.length ?? 0).toBe(1);
    expect(bySchemaMat.get("lix_commit")?.length ?? 0).toBe(1);
    expect(bySchemaMat.get("lix_change_set")?.length ?? 0).toBe(0);
    expect(bySchemaMat.get("lix_commit_edge")?.length ?? 0).toBe(1);
    expect(bySchemaMat.get("lix_version_tip")?.length ?? 0).toBe(1);
    // Only domain CSEs: 1 entity
    expect(bySchemaMat.get("lix_change_set_element")?.length ?? 0).toBe(1);
    // Totals under drop dual commit (domain + authors(materialized) + meta, no change_set row, no meta CSEs)
    expect(res.changes).toHaveLength(3);
    expect(res.materializedState).toHaveLength(6);
});
test("generateCommit includes domain writer_key in materialized state", () => {
    const t = "2025-01-01T00:00:00.000Z";
    const versions = new Map([
        [
            "v1",
            {
                parent_commit_ids: [],
                snapshot: {
                    id: "v1",
                    name: "v1",
                    working_commit_id: null,
                    inherits_from_version_id: null,
                    hidden: 0,
                    commit_id: "parent",
                },
            },
        ],
        [
            "global",
            {
                parent_commit_ids: [],
                snapshot: {
                    id: "global",
                    name: "global",
                    working_commit_id: null,
                    inherits_from_version_id: null,
                    hidden: 0,
                    commit_id: "g-parent",
                },
            },
        ],
    ]);
    const changes = [
        {
            id: "c1",
            entity_id: "e1",
            schema_key: "mock_schema",
            schema_version: "1.0",
            file_id: "f1",
            plugin_key: "plugin",
            snapshot_content: JSON.stringify({ x: 1 }),
            created_at: t,
            // extra props consumed by generator
            version_id: "v1",
            writer_key: "writer:test",
        },
    ];
    const res = generateCommit({
        timestamp: t,
        activeAccounts: [],
        changes,
        versions,
        generateUuid: () => "u",
    });
    // Domain row must be present with writer_key
    const domainMat = res.materializedState.find((m) => m.schema_key === "mock_schema" && m.entity_id === "e1");
    expect(domainMat).toBeDefined();
    expect(domainMat.writer_key).toBe("writer:test");
    // Meta rows should not carry writer_key (null)
    const meta = res.materializedState.filter((m) => m.schema_key !== "mock_schema");
    expect(meta.length).toBeGreaterThan(0);
    for (const m of meta) {
        expect(m.writer_key ?? null).toBeNull();
    }
});
test("scenario 2: 1 key_value on global (with author)", async () => {
    const lix = await openLix({
        keyValues: [
            {
                key: "lix_deterministic_mode",
                value: { enabled: true },
                lixcol_version_id: "global",
            },
        ],
    });
    const now = await getTimestamp({ lix });
    const chgId = "chg_global";
    const userChange = {
        id: chgId,
        entity_id: "kv_global",
        schema_key: "lix_key_value",
        schema_version: "1.0",
        file_id: "lix",
        plugin_key: "lix_sdk",
        snapshot_content: JSON.stringify({ key: "g", value: "1" }),
        created_at: now,
        version_id: "global",
    };
    const preIds3 = [
        await uuidV7({ lix }),
        await uuidV7({ lix }),
        await uuidV7({ lix }),
    ];
    const res = generateCommit({
        timestamp: now,
        activeAccounts: ["acct-1"],
        changes: [userChange],
        versions: new Map([
            [
                "global",
                {
                    parent_commit_ids: ["P_global"],
                    snapshot: {
                        id: "global",
                        name: "global",
                        commit_id: "ignore",
                        working_commit_id: "work-global",
                        inherits_from_version_id: null,
                        hidden: true,
                    },
                },
            ],
        ]),
        generateUuid: () => preIds3.shift() || "uuid_fallback",
    });
    const bySchema = groupBySchema(res.changes);
    // Only global participates
    expect(bySchema.get("lix_key_value")?.length ?? 0).toBe(1);
    expect(bySchema.get("lix_change_author")?.length ?? 0).toBe(0);
    expect(bySchema.get("lix_commit")?.length ?? 0).toBe(1);
    // change_set is synthesized in cache (no change row)
    expect(bySchema.get("lix_change_set")?.length ?? 0).toBe(0);
    expect(bySchema.get("lix_commit_edge")?.length ?? 0).toBe(0);
    // Version pointer updates are recorded as lix_version_tip
    expect(bySchema.get("lix_version_tip")?.length ?? 0).toBe(1);
    // No descriptor writes during commit; descriptor is domain-only bootstrap/update
    expect(bySchema.get("lix_version_descriptor")?.length ?? 0).toBe(0);
    // Step 1: no CSE change rows
    expect(bySchema.get("lix_change_set_element")?.length ?? 0).toBe(0);
    const commit = JSON.parse(bySchema.get("lix_commit")[0].snapshot_content);
    // Step 1: commit snapshot includes change_ids for derivation
    expect(typeof commit.change_set_id).toBe("string");
    // version_id/author_account_ids are no longer on commit snapshots
    expect(commit.version_id).toBeUndefined();
    expect(commit.meta_change_ids?.length ?? 0).toBe(1);
    // Commit-level authors
    expect(commit.author_account_ids).toEqual(["acct-1"]);
    expect(commit.parent_commit_ids).toEqual(["P_global"]);
    const bySchemaMat2 = groupBySchema(res.materializedState ?? []);
    expect(bySchemaMat2.get("lix_key_value")?.length ?? 0).toBe(1);
    expect(bySchemaMat2.get("lix_change_author")?.length ?? 0).toBe(1);
    expect(bySchemaMat2.get("lix_commit")?.length ?? 0).toBe(1);
    expect(bySchemaMat2.get("lix_change_set")?.length ?? 0).toBe(0);
    expect(bySchemaMat2.get("lix_commit_edge")?.length ?? 0).toBe(1);
    expect(bySchemaMat2.get("lix_version_tip")?.length ?? 0).toBe(1);
    // Only domain CSEs: 1 entity
    expect(bySchemaMat2.get("lix_change_set_element")?.length ?? 0).toBe(1);
    // Totals under drop dual commit (domain + authors(materialized) + meta, no change_set row, no meta CSEs)
    expect(res.changes).toHaveLength(3);
    expect(res.materializedState).toHaveLength(6);
});
test("scenario 3: 2 key_values (active + global), each with both authors", async () => {
    const lix = await openLix({
        keyValues: [
            {
                key: "lix_deterministic_mode",
                value: { enabled: true },
                lixcol_version_id: "global",
            },
        ],
    });
    const now = await getTimestamp({ lix });
    const changeA = {
        id: "chg_A",
        entity_id: "kv_A",
        schema_key: "lix_key_value",
        schema_version: "1.0",
        file_id: "lix",
        plugin_key: "lix_sdk",
        snapshot_content: JSON.stringify({ key: "A", value: "1" }),
        created_at: now,
        version_id: "global",
    };
    const changeB = {
        id: "chg_B",
        entity_id: "kv_B",
        schema_key: "lix_key_value",
        schema_version: "1.0",
        file_id: "lix",
        plugin_key: "lix_sdk",
        snapshot_content: JSON.stringify({ key: "B", value: "1" }),
        created_at: now,
        version_id: "version-main",
    };
    const preIds4 = [
        await uuidV7({ lix }),
        await uuidV7({ lix }),
        await uuidV7({ lix }),
    ];
    const res = generateCommit({
        timestamp: now,
        activeAccounts: ["acct-1", "acct-2"],
        changes: [changeA, changeB],
        versions: new Map([
            [
                "global",
                {
                    parent_commit_ids: ["P_global"],
                    snapshot: {
                        id: "global",
                        name: "global",
                        commit_id: "ignore",
                        working_commit_id: "work-global",
                        inherits_from_version_id: null,
                        hidden: true,
                    },
                },
            ],
            [
                "version-main",
                {
                    parent_commit_ids: ["P_active"],
                    snapshot: {
                        id: "version-main",
                        name: "main",
                        commit_id: "ignore",
                        working_commit_id: "work-main",
                        inherits_from_version_id: "global",
                        hidden: false,
                    },
                },
            ],
        ]),
        generateUuid: () => preIds4.shift() || "uuid_fallback",
    });
    const bySchema = groupBySchema(res.changes);
    expect(bySchema.get("lix_key_value")?.length ?? 0).toBe(2);
    expect(bySchema.get("lix_change_author")?.length ?? 0).toBe(0);
    expect(bySchema.get("lix_commit")?.length ?? 0).toBe(2);
    // change_set is synthesized in cache (no change rows)
    expect(bySchema.get("lix_change_set")?.length ?? 0).toBe(0);
    expect(bySchema.get("lix_commit_edge")?.length ?? 0).toBe(0);
    // Version pointer updates are recorded as lix_version_tip
    expect(bySchema.get("lix_version_tip")?.length ?? 0).toBe(2);
    // No descriptor writes during commit; descriptor is domain-only bootstrap/update
    expect(bySchema.get("lix_version_descriptor")?.length ?? 0).toBe(0);
    // Step 1: no CSE change rows
    expect(bySchema.get("lix_change_set_element")?.length ?? 0).toBe(0);
    const commits = (bySchema.get("lix_commit") || []).map((c) => JSON.parse(c.snapshot_content));
    // Step 1: commit snapshot includes change_ids for derivation
    commits.forEach((c) => {
        expect(typeof c.change_set_id).toBe("string");
        // version_id/author_account_ids are no longer on commit snapshots
        expect(c.version_id).toBeUndefined();
        expect(c.meta_change_ids?.length ?? 0).toBe(1);
        expect(c.author_account_ids).toEqual(["acct-1", "acct-2"]);
    });
    const bySchemaMat3 = groupBySchema(res.materializedState ?? []);
    expect(bySchemaMat3.get("lix_key_value")?.length ?? 0).toBe(2);
    expect(bySchemaMat3.get("lix_change_author")?.length ?? 0).toBe(4);
    expect(bySchemaMat3.get("lix_commit")?.length ?? 0).toBe(2);
    expect(bySchemaMat3.get("lix_change_set")?.length ?? 0).toBe(0);
    expect(bySchemaMat3.get("lix_commit_edge")?.length ?? 0).toBe(2);
    // Version tips are materialized in hot write-through
    expect(bySchemaMat3.get("lix_version_tip")?.length ?? 0).toBe(2);
    // Only domain CSEs are materialized: 2 entities
    expect(bySchemaMat3.get("lix_change_set_element")?.length ?? 0).toBe(2);
    expect(res.changes).toHaveLength(6);
    expect(res.materializedState).toHaveLength(14);
});
//# sourceMappingURL=generate-commit.test.js.map