import { sql } from "kysely";
import { LixActiveAccountSchema } from "./schema-definition.js";
import { test, expect } from "vitest";
import { openLix } from "../lix/open-lix.js";
import { createVersion } from "../version/create-version.js";
import { createPreprocessor } from "../engine/preprocessor/create-preprocessor.js";
test("insert, update, delete on the account view", async () => {
    const lix = await openLix({});
    await lix.db
        .insertInto("account")
        .values([
        {
            id: "account0",
            name: "Alice",
        },
        {
            id: "account1",
            name: "Bob",
        },
    ])
        .execute();
    const viewAfterInsert = await lix.db
        .selectFrom("account")
        .select(["id", "name"])
        .where("id", "in", ["account0", "account1"])
        .orderBy("id")
        .execute();
    expect(viewAfterInsert).toEqual([
        {
            id: "account0",
            name: "Alice",
        },
        {
            id: "account1",
            name: "Bob",
        },
    ]);
    await lix.db
        .updateTable("account")
        .where("id", "=", "account0")
        .set({
        name: "Alice Updated",
    })
        .execute();
    const viewAfterUpdate = await lix.db
        .selectFrom("account")
        .orderBy("id")
        .where("id", "in", ["account0", "account1"])
        .select(["id", "name"])
        .execute();
    expect(viewAfterUpdate).toEqual([
        {
            id: "account0",
            name: "Alice Updated",
        },
        {
            id: "account1",
            name: "Bob",
        },
    ]);
    await lix.db.deleteFrom("account").where("id", "=", "account0").execute();
    const viewAfterDelete = await lix.db
        .selectFrom("account")
        .orderBy("id")
        .where("id", "in", ["account0", "account1"])
        .select(["id", "name"])
        .execute();
    expect(viewAfterDelete).toEqual([
        {
            id: "account1",
            name: "Bob",
        },
    ]);
});
test("account ids should have a default", async () => {
    const lix = await openLix({});
    await lix.db
        .insertInto("account")
        .values({
        name: "Test User",
    })
        .execute();
    const account = await lix.db
        .selectFrom("account")
        .where("name", "=", "Test User")
        .selectAll()
        .executeTakeFirstOrThrow();
    expect(account.id).toBeDefined();
    expect(account.name).toBe("Test User");
});
test("account operations are version specific and isolated", async () => {
    const lix = await openLix({});
    const versionA = await createVersion({
        lix,
        id: "versionA",
    });
    const versionB = await createVersion({
        lix,
        id: "versionB",
    });
    // Insert account in version A
    await lix.db
        .insertInto("account_by_version")
        .values({
        id: "accountA",
        name: "User A",
        lixcol_version_id: versionA.id,
    })
        .execute();
    // Insert account in version B with same id but different name
    await lix.db
        .insertInto("account_by_version")
        .values({
        id: "accountB",
        name: "User B",
        lixcol_version_id: versionB.id,
    })
        .execute();
    // Verify both versions have their own accounts
    const accountsInVersionA = await lix.db
        .selectFrom("account_by_version")
        .where("lixcol_version_id", "=", versionA.id)
        .where("id", "in", ["accountA", "accountB"])
        .selectAll()
        .execute();
    const accountsInVersionB = await lix.db
        .selectFrom("account_by_version")
        .where("lixcol_version_id", "=", versionB.id)
        .where("id", "in", ["accountA", "accountB"])
        .selectAll()
        .execute();
    expect(accountsInVersionA).toHaveLength(1);
    expect(accountsInVersionB).toHaveLength(1);
    expect(accountsInVersionA[0]?.name).toBe("User A");
    expect(accountsInVersionB[0]?.name).toBe("User B");
    // Update account in version A
    await lix.db
        .updateTable("account_by_version")
        .where("id", "=", "accountA")
        .where("lixcol_version_id", "=", versionA.id)
        .set({
        name: "User A Updated",
    })
        .execute();
    // Verify update only affected version A
    const updatedAccountsA = await lix.db
        .selectFrom("account_by_version")
        .where("lixcol_version_id", "=", versionA.id)
        .where("id", "=", "accountA")
        .selectAll()
        .execute();
    const unchangedAccountsB = await lix.db
        .selectFrom("account_by_version")
        .where("lixcol_version_id", "=", versionB.id)
        .where("id", "=", "accountB")
        .selectAll()
        .execute();
    expect(updatedAccountsA[0]?.name).toBe("User A Updated");
    expect(unchangedAccountsB[0]?.name).toBe("User B");
    // Delete account from version A
    await lix.db
        .deleteFrom("account_by_version")
        .where("id", "=", "accountA")
        .where("lixcol_version_id", "=", versionA.id)
        .execute();
    // Verify deletion only affected version A
    const remainingAccountsA = await lix.db
        .selectFrom("account_by_version")
        .where("id", "in", ["accountA", "accountB"])
        .where("lixcol_version_id", "=", versionA.id)
        .selectAll()
        .execute();
    const remainingAccountsB = await lix.db
        .selectFrom("account_by_version")
        .where("id", "in", ["accountA", "accountB"])
        .where("lixcol_version_id", "=", versionB.id)
        .selectAll()
        .execute();
    expect(remainingAccountsA).toHaveLength(0);
    expect(remainingAccountsB).toHaveLength(1);
    expect(remainingAccountsB[0]?.name).toBe("User B");
});
test("active_account temp table operations", async () => {
    const lix = await openLix({});
    // No accounts should exist by default
    const activeAccounts = await lix.db
        .selectFrom("active_account as aa")
        .innerJoin("account_by_version as a", "a.id", "aa.account_id")
        .where("a.lixcol_version_id", "=", "global")
        .select(["aa.account_id", "a.id", "a.name"])
        .execute();
    expect(activeAccounts).toHaveLength(0);
    // First create a real account in global version (where active accounts look)
    await lix.db
        .insertInto("account_by_version")
        .values({
        id: "user123",
        name: "Alice",
        lixcol_version_id: "global",
    })
        .execute();
    // Then make it active
    await lix.db
        .insertInto("active_account")
        .values({
        account_id: "user123",
    })
        .execute();
    const updatedActiveAccounts = await lix.db
        .selectFrom("active_account")
        .selectAll()
        .execute();
    expect(updatedActiveAccounts).toHaveLength(1);
    const aliceActive = updatedActiveAccounts.find((acc) => acc.account_id === "user123");
    expect(aliceActive).toBeDefined();
    expect(aliceActive?.account_id).toBe("user123");
    // Update the actual account (not the active account reference)
    await lix.db
        .updateTable("account_by_version")
        .where("id", "=", "user123")
        .where("lixcol_version_id", "=", "global")
        .set({ name: "Alice Updated" })
        .execute();
    const afterUpdate = await lix.db
        .selectFrom("active_account")
        .where("account_id", "=", "user123")
        .selectAll()
        .execute();
    expect(afterUpdate).toHaveLength(1);
    // Verify the account was updated by checking the actual account
    const updatedAccount = await lix.db
        .selectFrom("account_by_version")
        .where("id", "=", "user123")
        .where("lixcol_version_id", "=", "global")
        .selectAll()
        .executeTakeFirst();
    expect(updatedAccount?.name).toBe("Alice Updated");
    // Delete active account
    await lix.db
        .deleteFrom("active_account")
        .where("account_id", "=", "user123")
        .execute();
    const afterDelete = await lix.db
        .selectFrom("active_account")
        .selectAll()
        .execute();
    expect(afterDelete).toHaveLength(0);
});
test("account tables start empty until an account is created", async () => {
    const lix = await openLix({});
    const allAccounts = await lix.db
        .selectFrom("account_by_version")
        .selectAll()
        .execute();
    expect(allAccounts.length).toBe(0);
    const activeAccount = await lix.db
        .selectFrom("active_account as aa")
        .innerJoin("account_by_version as a", "a.id", "aa.account_id")
        .where("a.lixcol_version_id", "=", "global")
        .select(["aa.account_id", "a.id", "a.name"])
        .executeTakeFirst();
    expect(activeAccount).toBeUndefined();
});
test("active_account should enforce foreign key constraint on account_id", async () => {
    const lix = await openLix({});
    // Try to insert an active account reference to a non-existent account
    await expect(lix.db
        .insertInto("active_account")
        .values({
        account_id: "non-existent-account",
    })
        .execute()).rejects.toThrow(/foreign key/i);
});
test("active_account view injects global version defaults", async () => {
    const lix = await openLix({});
    await lix.db
        .insertInto("account_by_version")
        .values({
        id: "acct-1",
        name: "Global User",
        lixcol_version_id: "global",
    })
        .execute();
    await lix.db
        .insertInto("active_account")
        .values({ account_id: "acct-1" })
        .execute();
    const row = await lix.db
        .selectFrom("state_by_version")
        .select([
        "schema_key",
        "file_id",
        "plugin_key",
        "version_id",
        "untracked",
        "inherited_from_version_id",
    ])
        .where("schema_key", "=", "lix_active_account")
        .where("inherited_from_version_id", "is", "global")
        .where("entity_id", "=", "acct-1")
        .executeTakeFirstOrThrow();
    expect(row).toMatchObject({
        schema_key: "lix_active_account",
        file_id: "lix",
        plugin_key: "lix_sdk",
        untracked: 1,
    });
    expect(row.version_id).toBeDefined();
    const activeVersion = await lix.db
        .selectFrom("active_version")
        .select(["lixcol_inherited_from_version_id"])
        .executeTakeFirstOrThrow();
    expect(activeVersion.lixcol_inherited_from_version_id).toBe("global");
    await lix.close();
});
test("active_account schema exposes only the base view", async () => {
    const lix = await openLix({});
    const storedSchema = {
        ...LixActiveAccountSchema,
        "x-lix-version": "1.1",
    };
    await lix.db
        .insertInto("stored_schema")
        .values({ value: storedSchema })
        .execute();
    const preprocess = createPreprocessor({ engine: lix.engine });
    const rewritten = preprocess({
        sql: "SELECT * FROM active_account_by_version",
        parameters: [],
    });
    expect(rewritten.sql).toContain("active_account_by_version");
    expect(rewritten.sql).not.toContain("schema_key = 'lix_active_account'");
    await expect(sql `SELECT * FROM active_account_by_version`.execute(lix.db)).rejects.toThrow(/no such table/i);
    await expect(sql `SELECT * FROM active_account_history`.execute(lix.db)).rejects.toThrow(/no such table/i);
    await lix.close();
});
//# sourceMappingURL=schema.test.js.map