import { drizzle } from "drizzle-orm/postgres-js";
import { migrate } from "drizzle-orm/postgres-js/migrator";
import postgres from "postgres";
import { fileURLToPath } from "url";
import path from "path";

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

const migrationUrl = process.env.DATABASE_DIRECT_URL || process.env.DATABASE_URL;
if (!migrationUrl) {
  console.error("ERROR: DATABASE_URL (or DATABASE_DIRECT_URL) is required");
  process.exit(1);
}

console.log("Running database migrations...");
const client = postgres(migrationUrl, {
  max: 1,
  onnotice: () => {}, // suppress NOTICE messages (schema/table already exists, etc.)
});

try {
  const db = drizzle(client);
  await migrate(db, { migrationsFolder: path.resolve(__dirname, "../drizzle") });
  console.log("Migrations completed successfully");
} catch (err) {
  console.error("Migration failed:", err);
  await client.end().catch(() => {});
  process.exit(1);
}

// ── Clerk → BetterAuth one-time data migration ────────────────────────────────
// FK conversion and email_verified always run (idempotent WHERE clauses).
// OAuth account import only runs when CLERK_SECRET_KEY is set.

console.log("Running FK conversion...");
try {
  await convertForeignKeys(client);
} catch (err) {
  console.error("FK conversion failed:", err);
  await client.end().catch(() => {});
  process.exit(1);
}

const CLERK_SECRET_KEY = process.env.CLERK_SECRET_KEY;

if (!CLERK_SECRET_KEY) {
  console.log("CLERK_SECRET_KEY not set — skipping Clerk OAuth account import");
} else {
  console.log("Running Clerk OAuth account import...");
  try {
    await importClerkOAuthAccounts(client, CLERK_SECRET_KEY);
    console.log("Clerk OAuth account import complete");
  } catch (err) {
    console.error("Clerk OAuth account import failed:", err);
    await client.end().catch(() => {});
    process.exit(1);
  }
}

await client.end().catch(() => {});
process.exit(0);

// ─────────────────────────────────────────────────────────────────────────────

async function convertForeignKeys(sql) {
  // Convert teams.owner_id from Clerk IDs to users.id UUIDs.
  // Safe to run repeatedly — WHERE clause only matches unconverted rows.
  const teamsResult = await sql`
    UPDATE teams t
    SET owner_id = u.id::text
    FROM users u
    WHERE t.owner_id = u.clerk_id
      AND u.clerk_id IS NOT NULL
  `;
  console.log(`  teams.owner_id: ${teamsResult.count} rows converted`);

  // Convert commissioners.user_id from Clerk IDs to users.id UUIDs
  const commissResult = await sql`
    UPDATE commissioners c
    SET user_id = u.id::text
    FROM users u
    WHERE c.user_id = u.clerk_id
      AND u.clerk_id IS NOT NULL
  `;
  console.log(`  commissioners.user_id: ${commissResult.count} rows converted`);

  // Convert leagues.created_by from Clerk IDs to users.id UUIDs
  const leaguesResult = await sql`
    UPDATE leagues l
    SET created_by = u.id::text
    FROM users u
    WHERE l.created_by = u.clerk_id
      AND u.clerk_id IS NOT NULL
  `;
  console.log(`  leagues.created_by: ${leaguesResult.count} rows converted`);

  // Mark all Clerk users as email-verified (they already verified via Clerk)
  await sql`
    UPDATE users
    SET email_verified = true
    WHERE clerk_id IS NOT NULL
      AND email_verified = false
  `;

  // Grandfather pre-enforcement BetterAuth signups: they have no clerk_id and
  // registered before email verification was required.
  const grandfatherResult = await sql`
    UPDATE users
    SET email_verified = true
    WHERE email_verified = false
      AND clerk_id IS NULL
  `;
  if (grandfatherResult.count > 0) {
    console.log(`  grandfathered ${grandfatherResult.count} pre-enforcement email/password users`);
  }
}

async function importClerkOAuthAccounts(sql, secretKey) {
  // Migrate OAuth accounts from Clerk into BetterAuth's accounts table.
  //    Skip entirely if any OAuth accounts already exist to avoid duplicates.
  //    We check only OAuth providers (not 'credential') so running migrate-clerk-passwords.mjs
  //    first doesn't prevent OAuth accounts from being created.
  const [{ count: existingCount }] = await sql`
    SELECT COUNT(*)::int AS count FROM accounts WHERE provider_id IN ('google', 'discord')
  `;
  if (existingCount > 0) {
    console.log(`  ${existingCount} OAuth accounts already exist — skipping Clerk account import`);
    return;
  }

  // Fetch all users with Clerk IDs from our DB
  const dbUsers = await sql`
    SELECT id, clerk_id FROM users WHERE clerk_id IS NOT NULL
  `;
  if (dbUsers.length === 0) {
    console.log("  No Clerk users found in DB — nothing to migrate");
    return;
  }
  console.log(`  Found ${dbUsers.length} Clerk users in DB, fetching from Clerk API...`);

  const dbUserByClerkId = new Map(dbUsers.map((u) => [u.clerk_id, u.id]));

  // Fetch all users from Clerk API (paginated)
  const clerkUsers = [];
  let offset = 0;
  const limit = 100;
  while (true) {
    const res = await fetch(
      `https://api.clerk.com/v1/users?limit=${limit}&offset=${offset}`,
      { headers: { Authorization: `Bearer ${secretKey}` } }
    );
    if (!res.ok) {
      throw new Error(`Clerk API error ${res.status}: ${await res.text()}`);
    }
    const batch = await res.json();
    clerkUsers.push(...batch);
    if (batch.length < limit) break;
    offset += limit;
  }
  console.log(`  Fetched ${clerkUsers.length} users from Clerk API`);

  let googleCount = 0;
  let discordCount = 0;
  let emailPasswordCount = 0;
  let skippedCount = 0;

  for (const clerkUser of clerkUsers) {
    const userId = dbUserByClerkId.get(clerkUser.id);
    if (!userId) {
      skippedCount++;
      continue;
    }

    for (const ext of clerkUser.external_accounts ?? []) {
      if (ext.provider === "google") {
        await sql`
          INSERT INTO accounts (id, account_id, provider_id, user_id, created_at, updated_at)
          SELECT
            gen_random_uuid()::text,
            ${ext.provider_user_id},
            'google',
            ${userId}::uuid,
            now(),
            now()
          WHERE NOT EXISTS (
            SELECT 1 FROM accounts
            WHERE user_id = ${userId}::uuid AND provider_id = 'google'
          )
        `;
        googleCount++;
      }

      if (ext.provider === "discord") {
        await sql`
          INSERT INTO accounts (id, account_id, provider_id, user_id, created_at, updated_at)
          SELECT
            gen_random_uuid()::text,
            ${ext.provider_user_id},
            'discord',
            ${userId}::uuid,
            now(),
            now()
          WHERE NOT EXISTS (
            SELECT 1 FROM accounts
            WHERE user_id = ${userId}::uuid AND provider_id = 'discord'
          )
        `;
        discordCount++;
      }
    }

    if (clerkUser.password_enabled) {
      emailPasswordCount++;
    }
  }

  console.log(
    `  Accounts created: ${googleCount} Google, ${discordCount} Discord`
  );
  if (emailPasswordCount > 0) {
    console.log(
      `  ${emailPasswordCount} email/password users — they must use "Forgot Password" on first login`
    );
  }
  if (skippedCount > 0) {
    console.log(`  Skipped ${skippedCount} Clerk users with no matching DB row`);
  }
}
