/**
 * Live Postgres/MySQL integration tests. These are GATED on env vars so the
 * normal `bun test` run stays green without a database:
 *
 *   WRNEXUS_PG_URL=postgres://…   WRNEXUS_MYSQL_URL=mysql://…   bun test packages/db
 *
 * The `bun run test:db:live` script spins up both via docker-compose, sets the
 * env vars, runs this file, and tears the containers down.
 */
import { test, expect } from "bun:test";
import { v, table, createDb, createTableSql, paginate, type Dialect } from "../src/index.ts";
import { bunSql } from "../src/adapters/bunsql.ts";

const users = table<{ id: number; email: string; name: string; active: boolean }>("users", {
  id: v.id(),
  email: v.string().unique(),
  name: v.string(),
  active: v.boolean().default(true),
});

const targets: { dialect: Dialect; url: string }[] = [];
if (process.env.WRNEXUS_PG_URL)
  targets.push({ dialect: "postgres", url: process.env.WRNEXUS_PG_URL });
if (process.env.WRNEXUS_MYSQL_URL)
  targets.push({ dialect: "mysql", url: process.env.WRNEXUS_MYSQL_URL });

const ph = (dialect: Dialect, i: number) => (dialect === "postgres" ? `$${i}` : "?");

if (targets.length === 0) {
  test.skip("live PG/MySQL (set WRNEXUS_PG_URL / WRNEXUS_MYSQL_URL to run)", () => {});
} else {
  for (const { dialect, url } of targets) {
    test(`${dialect}: DDL + CRUD + transaction + pagination`, async () => {
      const db = createDb(bunSql(url, dialect));
      try {
        await db.exec("DROP TABLE IF EXISTS users");
        await db.exec(createTableSql(users, dialect));

        for (let i = 1; i <= 5; i++) {
          await db.exec(
            `INSERT INTO users (email, name, active) VALUES (${ph(dialect, 1)}, ${ph(dialect, 2)}, ${ph(dialect, 3)})`,
            [`u${i}@x.com`, `U${i}`, true],
          );
        }

        const count = await db.one<{ n: number | string }>("SELECT COUNT(*) AS n FROM users");
        expect(Number(count?.n)).toBe(5);

        // Transaction rollback leaves the table unchanged.
        await db
          .tx(async (t) => {
            await t.exec(
              `INSERT INTO users (email, name, active) VALUES (${ph(dialect, 1)}, ${ph(dialect, 2)}, ${ph(dialect, 3)})`,
              ["rollback@x.com", "R", true],
            );
            throw new Error("rollback");
          })
          .catch(() => {});
        const after = await db.one<{ n: number | string }>("SELECT COUNT(*) AS n FROM users");
        expect(Number(after?.n)).toBe(5);

        const page = await paginate(
          db,
          { sql: "SELECT * FROM users ORDER BY id", model: users },
          { page: 1, perPage: 2 },
        );
        expect(page.total).toBe(5);
        expect(page.totalPages).toBe(3);
        expect(page.items.length).toBe(2);

        await db.exec("DROP TABLE IF EXISTS users");
      } finally {
        await db.close();
      }
    });
  }
}
