import { readdir, readFile } from "node:fs/promises";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { pool } from "../db/client.js";

const currentFile = fileURLToPath(import.meta.url);
const migrationsDir = path.resolve(path.dirname(currentFile), "../../migrations");

async function ensureMigrationsTable() {
  await pool.query(`
    create table if not exists schema_migrations (
      id text primary key,
      applied_at timestamptz not null default now()
    );
  `);
}

async function hasMigration(id: string) {
  const result = await pool.query<{ exists: boolean }>(
    "select exists(select 1 from schema_migrations where id = $1) as exists",
    [id]
  );
  return result.rows[0]?.exists ?? false;
}

async function applyMigration(id: string, sql: string) {
  await pool.query("begin");
  try {
    await pool.query(sql);
    await pool.query("insert into schema_migrations (id) values ($1)", [id]);
    await pool.query("commit");
  } catch (error) {
    await pool.query("rollback");
    throw error;
  }
}

async function main() {
  await ensureMigrationsTable();

  const files = (await readdir(migrationsDir))
    .filter((file) => file.endsWith(".sql"))
    .sort((a, b) => a.localeCompare(b));

  for (const file of files) {
    if (await hasMigration(file)) {
      console.log(`Skipping ${file}`);
      continue;
    }

    const sql = await readFile(path.join(migrationsDir, file), "utf8");
    await applyMigration(file, sql);
    console.log(`Applied ${file}`);
  }

  await pool.end();
}

main().catch(async (error) => {
  console.error(error);
  await pool.end();
  process.exitCode = 1;
});
