export interface WorkflowVariable {
  key: string;
  label: string;
  placeholder?: string;
  default?: string;
  required?: boolean;
}

const tokenRegex = () => /\{\{\s*([\w-]+)\s*\}\}/g;
const placeholderRegex = () => /\[[^[\]\n]+\]/g;

const humanize = (key: string) =>
  key.replace(/[_-]+/g, ' ').trim().replace(/\b\w/g, (char) => char.toUpperCase());

/** Ordered, de-duplicated `{{key}}` tokens found in a template. */
export const parseVariableKeys = (template: string): string[] => {
  const keys: string[] = [];
  for (const match of template.matchAll(tokenRegex())) {
    if (!keys.includes(match[1])) keys.push(match[1]);
  }
  return keys;
};

/** Merge the template's `{{key}}` tokens with any existing variable metadata. */
export const deriveVariables = (
  template: string,
  existing: WorkflowVariable[] = [],
): WorkflowVariable[] => {
  const byKey = new Map(existing.map((variable) => [variable.key, variable]));
  return parseVariableKeys(template).map(
    (key) => byKey.get(key) ?? { key, label: humanize(key) },
  );
};

/**
 * Expand a template into composer "fill" text: each `{{key}}` becomes its default
 * value, or a `[Label]` placeholder token the user can type over / Tab between.
 */
export const expandForFill = (template: string, variables: WorkflowVariable[]): string => {
  const byKey = new Map(variables.map((variable) => [variable.key, variable]));
  return template.replace(tokenRegex(), (_, key: string) => {
    const variable = byKey.get(key);
    if (variable?.default) return variable.default;
    return `[${variable?.label ?? humanize(key)}]`;
  });
};

/** Range of the first `[placeholder]` token in `text`, or null. */
export const findFirstPlaceholder = (text: string): [number, number] | null => {
  const match = placeholderRegex().exec(text);
  return match ? [match.index, match.index + match[0].length] : null;
};

/** Range of the next `[placeholder]` at or after `from` (wraps to the first), or null. */
export const findNextPlaceholder = (text: string, from: number): [number, number] | null => {
  const matches = [...text.matchAll(placeholderRegex())];
  if (matches.length === 0) return null;
  const next = matches.find((match) => (match.index ?? 0) >= from) ?? matches[0];
  const index = next.index ?? 0;
  return [index, index + next[0].length];
};
