        text = re.sub(VARIABLE_PATTERN, replace_fn, text)

        # Generated / configured values second pass
        gen_map = {
            "RandomInvoiceNumber": generated.invoice_number,
            "RandomTotal": f"${generated.amount:,.2f}" if generated.amount is not None else None,
            "RandomShippingCharge": f"${generated.shipping:,.2f}" if generated.shipping is not None else None,
            "RandomName": generated.random_name,
            "InvoiceDate": generated.invoice_date,
            "DueDate": generated.due_date,
            "CompanyPhone": generated.phone,
            "UnsubscribeLink": extra.get("unsubscribe_link", ""),
        }
        for var, val in gen_map.items():
            if val not in (None, ""):
                text = text.replace(f"%{var}%", str(val))
                used.append(var)
        return SubstitutionResult(text=text, unknown=sorted(set(unknown)), missing=sorted(set(missing)), used=sorted(set(used)))

    # ------------------------------------------------------------------ analysis
    def analyze(self, text: str, custom_fields: Optional[list] = None) -> dict:
        """Report which variables a template uses and any unknown ones (pre-send validation)."""
        found = set(VARIABLE_PATTERN.findall(text or ""))
        custom_fields = set(custom_fields or [])
        unknown = sorted(found - KNOWN_VARIABLES - custom_fields)
        return {"variables": sorted(found), "unknown": unknown}


def analyze_template_variables(text: str, custom_fields: Optional[list] = None) -> dict:
    return VariableEngine().analyze(text, custom_fields)
