import { describe, expect, test } from "bun:test";
import { authzMigrationSql } from "../src/migrations.ts";

/**
 * The postgres/mysql DDL is generated but never exercised against a real
 * server in this repo, so it has to be asserted statically: the id column
 * type, the `effect` CHECK constraint (an unrecognised value must not vanish
 * from both the grant and deny buckets), the MySQL binary collation (so
 * tenant "T1" cannot match "t1" and role "admin" cannot collapse with
 * "Admin"), and both UNIQUE constraints, per dialect.
 */
describe("authzMigrationSql", () => {
  test("sqlite: autoincrement id, no collation, both constraints", () => {
    const { up, down } = authzMigrationSql("sqlite");
    expect(up).toHaveLength(2);
    const [assignment, grant] = up;

    expect(assignment).toContain("id INTEGER PRIMARY KEY AUTOINCREMENT");
    expect(assignment).toContain(
      "CONSTRAINT _wrn_authz_assignment_unique UNIQUE (subject_id, scope, role)",
    );
    expect(assignment).not.toContain("COLLATE");

    expect(grant).toContain("id INTEGER PRIMARY KEY AUTOINCREMENT");
    expect(grant).toContain("effect VARCHAR(16) NOT NULL CHECK (effect IN ('allow', 'deny'))");
    expect(grant).toContain(
      "CONSTRAINT _wrn_authz_grant_unique UNIQUE (subject_id, scope, permission)",
    );
    expect(grant).not.toContain("COLLATE");

    expect(down).toEqual([
      "DROP TABLE IF EXISTS _wrn_authz_grant",
      "DROP TABLE IF EXISTS _wrn_authz_assignment",
    ]);
  });

  test("postgres: SERIAL id, no collation, both constraints", () => {
    const { up } = authzMigrationSql("postgres");
    const [assignment, grant] = up;

    expect(assignment).toContain("id SERIAL PRIMARY KEY");
    expect(assignment).toContain(
      "CONSTRAINT _wrn_authz_assignment_unique UNIQUE (subject_id, scope, role)",
    );
    expect(assignment).not.toContain("COLLATE");

    expect(grant).toContain("id SERIAL PRIMARY KEY");
    expect(grant).toContain("effect VARCHAR(16) NOT NULL CHECK (effect IN ('allow', 'deny'))");
    expect(grant).toContain(
      "CONSTRAINT _wrn_authz_grant_unique UNIQUE (subject_id, scope, permission)",
    );
    expect(grant).not.toContain("COLLATE");
  });

  test("mysql: AUTO_INCREMENT id, binary collation on identity columns, both constraints", () => {
    const { up } = authzMigrationSql("mysql");
    const [assignment, grant] = up;

    expect(assignment).toContain("id INT AUTO_INCREMENT PRIMARY KEY");
    expect(assignment).toContain("subject_id VARCHAR(255) COLLATE utf8mb4_bin NOT NULL");
    expect(assignment).toContain("scope VARCHAR(255) COLLATE utf8mb4_bin NOT NULL DEFAULT ''");
    expect(assignment).toContain("role VARCHAR(255) COLLATE utf8mb4_bin NOT NULL");
    expect(assignment).toContain(
      "CONSTRAINT _wrn_authz_assignment_unique UNIQUE (subject_id, scope, role)",
    );

    expect(grant).toContain("id INT AUTO_INCREMENT PRIMARY KEY");
    expect(grant).toContain("subject_id VARCHAR(255) COLLATE utf8mb4_bin NOT NULL");
    expect(grant).toContain("permission VARCHAR(255) COLLATE utf8mb4_bin NOT NULL");
    expect(grant).toContain("effect VARCHAR(16) NOT NULL CHECK (effect IN ('allow', 'deny'))");
    expect(grant).toContain(
      "CONSTRAINT _wrn_authz_grant_unique UNIQUE (subject_id, scope, permission)",
    );
  });
});
