import { dsnShort } from "./names";
import { normalizeDsn } from "./normalizeDsn";

/**
 * From the list of existingDsns, choose the ones that match the prefixes.
 * - When existingDsns is empty, when multiple entries in existingDsns match
 *   some prefix, or when no existingDsns entries match some prefix, then tries
 *   to treat that prefix as DSNs itself (and throws if it cannot).
 * - If requireMatch=true, each pattern must match exactly one existing DSN.
 */
export function chooseDsns({
  patterns,
  existingDsns,
  requireMatch,
}: {
  patterns: string[];
  existingDsns: string[];
  requireMatch: boolean;
}): [dsns: string[], warnings: string[]] {
  existingDsns = existingDsns.map((dsn) => normalizeDsn(dsn)!);

  const dsns: string[] = [];
  const warnings: string[] = [];
  for (const pattern of patterns) {
    let normalizedPattern: string | null = null;
    try {
      normalizedPattern = normalizeDsn(pattern)!;
    } catch (e: unknown) {
      if (typeof e !== "string") {
        throw e;
      }
    }

    const matched =
      normalizedPattern && existingDsns.some((dsn) => dsn === normalizedPattern)
        ? [normalizedPattern]
        : existingDsns.filter((dsn) => {
            if (pattern.match(/^\d+$/)) {
              return dsnShort(dsn).match(
                new RegExp(`(\\D|^)0*${pattern}(\\D|$)`),
              );
            } else {
              return (
                dsnShort(dsn).startsWith(pattern) ||
                (normalizedPattern &&
                  dsnShort(dsn) === dsnShort(normalizedPattern))
              );
            }
          });

    if (matched.length === 0) {
      if (requireMatch) {
        throw `No DSNs match "${pattern}".`;
      }

      try {
        dsns.push(normalizeDsn(pattern)!);
      } catch (e: unknown) {
        throw typeof e === "string" ? `No DSNs match "${pattern}". ${e}` : e;
      }
    } else if (matched.length === 1) {
      dsns.push(matched[0]);
    } else {
      if (requireMatch) {
        throw `Multiple DSNs match "${pattern}".`;
      }

      warnings.push(
        `Hint: multiple DSNs match "${pattern}", so treating it as an entire DSN.`,
      );
      try {
        dsns.push(normalizeDsn(pattern)!);
      } catch (e: unknown) {
        throw typeof e === "string"
          ? `Multiple DSNs match "${pattern}". ${e}`
          : e;
      }
    }
  }

  return [dsns, warnings];
}
