const crypto = require('node:crypto');
const fs = require('node:fs');
const path = require('node:path');
const postgres = require('postgres');

function readEnvFile(filePath) {
  if (!fs.existsSync(filePath)) {
    return {};
  }

  const content = fs.readFileSync(filePath, 'utf8');
  return Object.fromEntries(
    content
      .split(/\r?\n/)
      .map((line) => line.trim())
      .filter((line) => line && !line.startsWith('#') && line.includes('='))
      .map((line) => {
        const index = line.indexOf('=');
        const key = line.slice(0, index).trim();
        const value = line.slice(index + 1).trim();
        return [key, value];
      })
  );
}

function resolveDatabaseUrl() {
  if (process.env.DATABASE_URL) {
    return process.env.DATABASE_URL;
  }

  const rootDir = process.cwd();
  const envLocal = readEnvFile(path.join(rootDir, '.env.local'));
  if (envLocal.DATABASE_URL) {
    return envLocal.DATABASE_URL;
  }

  const env = readEnvFile(path.join(rootDir, '.env'));
  if (env.DATABASE_URL) {
    return env.DATABASE_URL;
  }

  throw new Error('DATABASE_URL was not found in process.env, .env.local, or .env');
}

function getMigrationFiles(rootDir) {
  return fs
    .readdirSync(path.join(rootDir, 'drizzle'))
    .filter((file) => file.endsWith('.sql'))
    .sort((left, right) => left.localeCompare(right));
}

async function main() {
  const databaseUrl = resolveDatabaseUrl();
  const databaseName = new URL(databaseUrl).pathname.replace(/^\//, '');
  const rootDir = process.cwd();
  const migrationFiles = getMigrationFiles(rootDir);

  if (!databaseName) {
    throw new Error('DATABASE_URL must include a database name');
  }

  const sql = postgres(databaseUrl, {
    max: 1,
    prepare: false
  });

  console.log(`Resetting database "${databaseName}"...`);
  try {
    await sql`
      select pg_terminate_backend(pid)
      from pg_stat_activity
      where datname = current_database()
        and pid <> pg_backend_pid()
    `;

    await sql.unsafe('drop schema if exists drizzle cascade');
    await sql.unsafe('drop schema if exists public cascade');
    await sql.unsafe('create schema public');
    await sql.unsafe('grant all on schema public to public');
    await sql.unsafe('grant all on schema public to postgres');
    await sql.unsafe('create schema drizzle');
    await sql.unsafe(`
      create table drizzle.__drizzle_migrations (
        id serial primary key,
        hash text not null,
        created_at bigint not null
      )
    `);

    for (const fileName of migrationFiles) {
      const filePath = path.join(rootDir, 'drizzle', fileName);
      const sqlContent = fs.readFileSync(filePath, 'utf8');
      const statements = sqlContent
        .split('--> statement-breakpoint')
        .map((statement) => statement.trim())
        .filter(Boolean);

      for (const statement of statements) {
        await sql.unsafe(statement);
      }

      const hash = crypto.createHash('sha256').update(sqlContent).digest('hex');
      await sql`
        insert into drizzle.__drizzle_migrations (hash, created_at)
        values (${hash}, ${String(Date.now())})
      `;
    }
  } finally {
    await sql.end();
  }

  console.log('Database reset completed.');
}

main().catch((error) => {
  console.error('Failed to reset database.');
  console.error(error);
  process.exit(1);
});
