use gas::prelude::*;
use universaldb::utils::IsolationLevel::*;

pub async fn run(ctx: &StandaloneCtx) -> Result<()> {
	// Actor runner name selector backfill
	if !is_complete(
		ctx,
		pegboard::workflows::actor_runner_name_selector_backfill::BACKFILL_NAME,
	)
	.await?
	{
		ctx.workflow(pegboard::workflows::actor_runner_name_selector_backfill::Input {})
			.unique()
			.dispatch()
			.await?;
	}

	// Serverless backfill
	if !is_complete(
		ctx,
		pegboard::workflows::serverless::backfill::BACKFILL_NAME,
	)
	.await?
	{
		ctx.workflow(pegboard::workflows::serverless::backfill::Input {})
			.unique()
			.dispatch()
			.await?;
	}

	// Epoxy backfill
	if !is_complete(ctx, epoxy::workflows::backfill::BACKFILL_NAME).await? {
		ctx.workflow(epoxy::workflows::backfill::Input { chunk_size: None })
			.tag("replica", ctx.config().epoxy_replica_id())
			.unique()
			.dispatch()
			.await?;
	}

	// Runner config backfill
	if !is_complete(
		ctx,
		pegboard::workflows::runner_pool_backfill::BACKFILL_NAME,
	)
	.await?
	{
		ctx.workflow(pegboard::workflows::runner_pool_backfill::Input {})
			.unique()
			.dispatch()
			.await?;
	}

	// Runner pool 2 backfill
	if !is_complete(
		ctx,
		pegboard::workflows::runner_pool2_backfill::BACKFILL_NAME,
	)
	.await?
	{
		ctx.workflow(pegboard::workflows::runner_pool2_backfill::Input {})
			.unique()
			.dispatch()
			.await?;
	}

	// Actor migration fix backfill
	if !is_complete(
		ctx,
		pegboard::workflows::actor_migration_fix_backfill::BACKFILL_NAME,
	)
	.await?
	{
		ctx.workflow(pegboard::workflows::actor_migration_fix_backfill::Input {})
			.unique()
			.dispatch()
			.await?;
	}

	Ok(())
}

async fn is_complete(ctx: &StandaloneCtx, name: &str) -> Result<bool> {
	let complete = ctx
		.udb()?
		.txn("bootstrap_check_backfill_complete", |tx| {
			let name = name.to_string();
			async move {
				let tx = tx.with_subspace(rivet_types::keys::backfill::subspace());
				tx.exists(
					&rivet_types::keys::backfill::CompleteKey::new(&name),
					Snapshot,
				)
				.await
			}
		})
		.custom_instrument(tracing::info_span!("check_backfill_complete_tx"))
		.await?;

	if complete {
		tracing::debug!(%name, "backfill already complete, skipping");
	}

	Ok(complete)
}
