import { URL } from "node:url";

interface DestructiveGuardOptions {
  commandName: string;
  allowedDatabaseNames?: string[];
  requireConfirmation?: boolean;
}

const PROTECTED_DATABASE_NAMES = new Set(["capakraken"]);

export function parseDatabaseUrl(rawUrl: string) {
  const parsed = new URL(rawUrl);
  const databaseName = parsed.pathname.replace(/^\/+/, "");

  return {
    protocol: parsed.protocol,
    hostname: parsed.hostname,
    port: parsed.port,
    databaseName,
    username: decodeURIComponent(parsed.username),
  };
}

export function formatTarget(target: ReturnType<typeof parseDatabaseUrl>) {
  const port = target.port ? `:${target.port}` : "";
  return `${target.protocol}//${target.username}@${target.hostname}${port}/${target.databaseName}`;
}

export function assertDestructiveDbAllowed({
  commandName,
  allowedDatabaseNames = [],
  requireConfirmation = true,
}: DestructiveGuardOptions) {
  const rawUrl = process.env.DATABASE_URL;

  if (!rawUrl) {
    throw new Error(`${commandName} aborted: DATABASE_URL is not configured.`);
  }

  const target = parseDatabaseUrl(rawUrl);
  const allowFlag = process.env.ALLOW_DESTRUCTIVE_DB_TOOLS === "true";
  const confirmationDb = process.env.CONFIRM_DESTRUCTIVE_DB_NAME;
  const allowlisted = allowedDatabaseNames.includes(target.databaseName);

  if (PROTECTED_DATABASE_NAMES.has(target.databaseName)) {
    throw new Error(
      `${commandName} aborted: database '${target.databaseName}' is explicitly protected from destructive tooling. Target=${formatTarget(target)}`,
    );
  }

  if (!allowlisted) {
    throw new Error(
      `${commandName} aborted: database '${target.databaseName}' is not in the destructive-tool allowlist (${allowedDatabaseNames.join(", ") || "none"}). Target=${formatTarget(target)}`,
    );
  }

  if (!allowFlag) {
    throw new Error(
      `${commandName} aborted: set ALLOW_DESTRUCTIVE_DB_TOOLS=true to allow destructive database operations. Target=${formatTarget(target)}`,
    );
  }

  if (requireConfirmation && confirmationDb !== target.databaseName) {
    throw new Error(
      `${commandName} aborted: set CONFIRM_DESTRUCTIVE_DB_NAME=${target.databaseName} to confirm the destructive target. Current value=${confirmationDb ?? "<unset>"}`,
    );
  }

  return target;
}
