import { existsSync } from "node:fs";
import { dirname, join, resolve } from "node:path";
import { fileURLToPath } from "node:url";
import { migrate } from "drizzle-orm/bun-sqlite/migrator";
import type { BunSQLiteDatabase } from "drizzle-orm/bun-sqlite";

const MIGRATION_JOURNAL_PATH = join("meta", "_journal.json");

export function applyDashboardMigrations(
  database: BunSQLiteDatabase<Record<string, unknown>>,
  migrationsFolder = resolveDashboardMigrationsFolder(),
) {
  migrate(database, { migrationsFolder });
}

export function resolveDashboardMigrationsFolder(
  explicitFolder = process.env.DASHBOARD_MIGRATIONS_DIR,
): string {
  if (explicitFolder) return assertMigrationFolder(resolve(explicitFolder));

  const cwdFolder = findMigrationFolder(process.cwd());
  if (cwdFolder) return cwdFolder;

  const moduleFolder = findMigrationFolder(dirname(fileURLToPath(import.meta.url)));
  if (moduleFolder) return moduleFolder;

  throw new Error(
    "Unable to locate dashboard Drizzle migrations. Set DASHBOARD_MIGRATIONS_DIR.",
  );
}

function findMigrationFolder(startPath: string): string | null {
  let currentPath = resolve(startPath);

  while (true) {
    const candidate = join(currentPath, "drizzle");
    if (hasMigrationJournal(candidate)) return candidate;

    const parentPath = dirname(currentPath);
    if (parentPath === currentPath) return null;
    currentPath = parentPath;
  }
}

function assertMigrationFolder(folder: string): string {
  if (hasMigrationJournal(folder)) return folder;
  throw new Error(`Dashboard migrations not found in ${folder}`);
}

function hasMigrationJournal(folder: string): boolean {
  return existsSync(join(folder, MIGRATION_JOURNAL_PATH));
}
