import {
  type VariableNode,
  type VariableNodeInput,
} from '../actions/InsertVariable/types';

const MUSTACHE_REGEX = /\{\{([^}]+)\}\}/g;

// Matches a <span data-variable-token="..."> that may contain one level of
// nested <span>…</span> (the bold category label emitted by TipTap's renderHTML).
const PILL_SPAN_REGEX =
  /<span[^>]*\bdata-variable-token="([^"]*)"[^>]*>(?:[^<]*(?:<span[^>]*>[^<]*<\/span>)?[^<]*)<\/span>/g;

/** Escapes characters that would break HTML attribute values. */
const escapeAttr = (s: string): string =>
  s.replace(/&/g, '&amp;').replace(/"/g, '&quot;').replace(/</g, '&lt;');

/**
 * Normalizes legacy variable shapes ({ id, token?, children? }) into
 * the canonical shape ({ key, children: [] }).
 */
export const normalizeVariables = (
  nodes: VariableNodeInput[],
): VariableNode[] =>
  nodes.map(node => {
    const legacy = node as Record<string, unknown>;
    const key = (legacy.key ?? legacy.id ?? '') as string;
    const children = Array.isArray(legacy.children)
      ? normalizeVariables(legacy.children as VariableNodeInput[])
      : [];

    return { key, label: node.label, children };
  });

/**
 * Recursively builds a map of { "parent.child": "Parent - Child" }
 * from the variable tree. Tokens are derived by concatenating keys
 * along the path (e.g. key "collaborator" → key "firstName" = "collaborator.firstName").
 */
export const buildTokenLabelMap = (
  variables: VariableNodeInput[],
  parentKey?: string,
  parentLabel?: string,
): Record<string, string> => {
  const map: Record<string, string> = {};
  const normalized = normalizeVariables(variables);

  for (const node of normalized) {
    const currentKey = parentKey ? `${parentKey}.${node.key}` : node.key;
    const currentLabel = parentLabel
      ? `${parentLabel} - ${node.label}`
      : node.label;

    if (node.children.length === 0) {
      map[currentKey] = currentLabel;
    } else {
      Object.assign(
        map,
        buildTokenLabelMap(node.children, currentKey, currentLabel),
      );
    }
  }

  return map;
};

export const prepareForEditor = (
  html: string,
  variables: VariableNodeInput[],
): string => {
  const labelMap = buildTokenLabelMap(variables);

  return html.replace(MUSTACHE_REGEX, (fullMatch, token: string) => {
    const label = labelMap[token];
    if (!label) return fullMatch;

    return `<span data-variable-token="${escapeAttr(token)}" data-variable-label="${escapeAttr(label)}" class="variable-pill">${escapeAttr(label)}</span>`;
  });
};

export const prepareForBackend = (html: string): string =>
  html.replace(PILL_SPAN_REGEX, (_match, token: string) => `{{${token}}}`);
