import { ensureTestDBExists } from "../../__tests__/internal/ensureTestDBExists";
import { mockTestStd } from "../../__tests__/internal/mockTestStd";
import { getSchemaName } from "../../internal/getSchemaName";
import { promiseAll } from "../../internal/promiseAll";
import { sql } from "../../internal/quote";
import { runSql } from "../../internal/runSql";
import { move } from "../move";

let fromDsn: string;
let toDsn: string;

beforeEach(async () => {
  [fromDsn, toDsn] = await promiseAll([
    ensureTestDBExists({
      from: 1,
      to: 1,
      state: "active",
    }),
    ensureTestDBExists({
      dbNameSuffix: "to",
    }),
  ]);
});

(process.env["IN_JEST_PROJECT"] ? test.skip : test)(
  "disabled FKs validation is transitive",
  async () => {
    const out = mockTestStd();
    try {
      await runSql(
        fromDsn,
        sql`
          CREATE TABLE sh0001.tbl(id serial PRIMARY KEY, s text);
          CREATE TABLE sh0001.child(
            id serial PRIMARY KEY,
            tbl_id bigint REFERENCES sh0001.tbl(id)
          );
        `,
      );
      await move({
        schema: await getSchemaName(fromDsn, 1),
        fromDsn,
        toDsn,
        commitAction: "deactivate-activate",
        validateFKs: false,
      });
      expect(await getFkIsValidated(toDsn, "sh0001", "child")).toEqual("f");

      await move({
        schema: await getSchemaName(fromDsn, 1),
        fromDsn: toDsn,
        toDsn: fromDsn,
        commitAction: "deactivate-activate",
        validateFKs: false,
      });
      expect(await getFkIsValidated(fromDsn, "sh0001", "child")).toEqual("f");

      await move({
        schema: await getSchemaName(fromDsn, 1),
        fromDsn,
        toDsn,
        commitAction: "deactivate-activate",
        validateFKs: true,
      });
      expect(await getFkIsValidated(toDsn, "sh0001", "child")).toEqual("t");
    } catch (e: unknown) {
      out.print();
      throw e;
    }
  },
);

async function getFkIsValidated(
  dsn: string,
  schema: string,
  table: string,
): Promise<"t" | "f" | null> {
  const result = await runSql.one(
    dsn,
    sql`
      SELECT convalidated
      FROM pg_namespace
      JOIN pg_class ON relnamespace = pg_namespace.oid
      JOIN pg_constraint ON conrelid = pg_class.oid
      WHERE nspname = ${schema} AND relname = ${table} AND contype = 'f'
      LIMIT 1
    `,
  );
  return result === "t" ? "t" : result === "f" ? "f" : null;
}
