<?php

namespace GriffinForms\Frontend\Html\Rules;

class FormRules extends \GriffinForms\Frontend\Html\Rules\Format
{
    protected $form;

    // Sets the current form instance for rule evaluation.
    public function setForm($form = null)
    {
        $this->form = $form;
    }

    // Outputs inline JavaScript used to evaluate conditional rules on the frontend.
    public function rulesJs()
    {
        if (!is_object($this->form) || !method_exists($this->form, 'getProp')) {
            return;
        }

        $form_id = absint($this->form->getProp('id'));
        if (0 === $form_id) {
            return;
        }

        $raw_rules = $this->form->getProp('conditional_logic');
        if (!is_array($raw_rules) || empty($raw_rules)) {
            return;
        }

        $normalized_rules = $this->normalizeRules($raw_rules);

        if (empty($normalized_rules)) {
            return;
        }

        $rules_json = wp_json_encode($normalized_rules);

        if (false === $rules_json) {
            return;
        }

        $inline_js = $this->buildRulesInlineJs($form_id, $normalized_rules, $rules_json);
        if ('' === $inline_js) {
            return;
        }

        wp_add_inline_script('griffinforms-frontend', $inline_js);
    }

    // Builds the inline JavaScript string that wires conditional logic on the frontend.
    protected function buildRulesInlineJs($form_id, array $normalized_rules, $rules_json)
    {
        ob_start();
        ?>
        jQuery(document).ready(function($) {
            <?php
            $this->renderRulesSetupJs($form_id, $rules_json);
            $this->renderResolutionHelpersJs();
            $this->renderEvaluationHelpersJs();
            $this->renderActionHelpersJs();
            $this->renderRuleExecutionJs($form_id, $normalized_rules);
            $this->renderRuleTriggersJs($form_id);
            ?>
        });
        <?php

        return trim(ob_get_clean());
    }

    // Emits core helper utilities shared by the rule evaluation scripts.
    protected function renderRulesSetupJs($form_id, $rules_json)
    {
        ?>
            const formId = <?php echo (int) $form_id; ?>;
            const formRulesConfig = <?php echo $rules_json; ?>;

            function getFieldControls(fieldId) {
                return $(".griffinforms-formcontrol-" + fieldId);
            }

            function getFieldContainer(fieldId) {
                const controls = getFieldControls(fieldId);
                if (controls.length) {
                    const container = controls.first().closest('.griffinforms-field-container');
                    if (container.length) {
                        return container;
                    }
                }

                return $('#griffinforms-field-' + fieldId);
            }

            function getRowContainer(rowId) {
                return $('#griffinforms-pagerow-' + rowId);
            }

            function convertDateValueToTimestamp(rawValue, format) {
                const source = (rawValue || '').toString().trim();
                if (!source.length) {
                    return null;
                }

                if (/^-?\d+$/.test(source)) {
                    const numericValue = parseInt(source, 10);
                    if (Number.isFinite(numericValue)) {
                        return numericValue;
                    }
                }

                let parsedDate = null;

                if ($.datepicker && typeof $.datepicker.parseDate === 'function') {
                    try {
                        parsedDate = $.datepicker.parseDate(format || 'yy-mm-dd', source);
                    } catch (error) {
                        parsedDate = null;
                    }
                }

                if (parsedDate instanceof Date && !Number.isNaN(parsedDate.getTime())) {
                    return Math.floor(Date.UTC(
                        parsedDate.getFullYear(),
                        parsedDate.getMonth(),
                        parsedDate.getDate()
                    ) / 1000);
                }

                const isoPattern = /^\s*(\d{4})-(\d{1,2})-(\d{1,2})\s*$/;
                const isoMatch = source.match(isoPattern);
                if (isoMatch) {
                    const year = parseInt(isoMatch[1], 10);
                    const month = parseInt(isoMatch[2], 10) - 1;
                    const day = parseInt(isoMatch[3], 10);

                    if (
                        Number.isFinite(year) && year >= 0 &&
                        Number.isFinite(month) && month >= 0 && month <= 11 &&
                        Number.isFinite(day) && day >= 1 && day <= 31
                    ) {
                        return Math.floor(Date.UTC(year, month, day) / 1000);
                    }
                }

                const fallback = Date.parse(source);
                if (Number.isFinite(fallback)) {
                    const fallbackDate = new Date(fallback);
                    if (!Number.isNaN(fallbackDate.getTime())) {
                        return Math.floor(Date.UTC(
                            fallbackDate.getFullYear(),
                            fallbackDate.getMonth(),
                            fallbackDate.getDate()
                        ) / 1000);
                    }
                }

                return null;
            }

            function getFieldValues(fieldId) {
                const controls = getFieldControls(fieldId);
                if (!controls.length) {
                    return [];
                }

                const collected = [];

                controls.each(function() {
                    const control = $(this);
                    const controlType = (control.attr('type') || '').toLowerCase();
                    const tagName = (control.prop('tagName') || '').toLowerCase();

                    if ('hidden' === controlType) {
                        const rawValue = control.val();
                        if (!rawValue) {
                            return;
                        }

                        try {
                            const parsed = JSON.parse(rawValue);
                            if (Array.isArray(parsed)) {
                                parsed.forEach(function(value) {
                                    if (value !== null && value !== undefined) {
                                        collected.push(String(value));
                                    }
                                });
                                return;
                            }

                            if (parsed !== null && typeof parsed === 'object') {
                                // Payment field: { items: [{name, product_id, ...}], gateway: "..." }
                                if (Array.isArray(parsed.items)) {
                                    parsed.items.forEach(function(item) {
                                        if (!item || typeof item !== 'object') { return; }
                                        const label = String(item.product_name || item.name || item.product_id || item.id || '');
                                        if (label.length) { collected.push(label); }
                                    });
                                    return;
                                }
                                Object.keys(parsed).forEach(function(key) {
                                    const val = parsed[key];
                                    if (val !== null && val !== undefined && !Array.isArray(val) && typeof val !== 'object' && String(val).length) {
                                        collected.push(String(val));
                                    }
                                });
                                return;
                            }

                            if (parsed !== null && typeof parsed !== 'object') {
                                collected.push(String(parsed));
                                return;
                            }
                        } catch (error) {
                            // Silently fall back to raw string when JSON parsing fails.
                        }

                        collected.push(String(rawValue));
                        return;
                    }

                    if ('select' === tagName) {
                        const optionValue = control.val();

                        if (Array.isArray(optionValue)) {
                            optionValue.forEach(function(value) {
                                if (value !== null && value !== undefined && String(value).length) {
                                    collected.push(String(value));
                                }
                            });
                        } else if (optionValue !== null && optionValue !== undefined && String(optionValue).length) {
                            collected.push(String(optionValue));
                        }

                        return;
                    }

                    const value = control.val();
                    if (value !== null && value !== undefined && String(value).length) {
                        const logicValueType = (control.attr('data-gf-logic-value-type') || '').toLowerCase();

                        if ('date' === logicValueType) {
                            const dateFormat = control.attr('data-gf-logic-date-format') || '';
                            const converted = convertDateValueToTimestamp(value, dateFormat);
                            if (converted !== null) {
                                collected.push(String(converted));
                                return;
                            }
                        }

                        collected.push(String(value));
                    }
                });

                if (!collected.length) {
                    const checkboxSelector = '.griffinforms-formcontrol-' + fieldId + '-checkbox:checked';
                    $(checkboxSelector).each(function() {
                        collected.push(String($(this).val()));
                    });

                    const radioSelector = '.griffinforms-formcontrol-' + fieldId + '-radio:checked';
                    const radios = $(radioSelector);
                    if (radios.length) {
                        const radioValue = radios.first().val();
                        if (radioValue !== undefined && radioValue !== null && String(radioValue).length) {
                            collected.push(String(radioValue));
                        }
                    }
                }

                return collected;
            }

            function getFieldValueCount(fieldId) {
                const controls = getFieldControls(fieldId);
                if (!controls.length) {
                    return 0;
                }

                let total = 0;

                controls.each(function() {
                    const control = $(this);
                    const controlType = (control.attr('type') || '').toLowerCase();
                    const tagName = (control.prop('tagName') || '').toLowerCase();

                    if ('hidden' === controlType) {
                        const rawValue = control.val();
                        if (!rawValue) {
                            return;
                        }

                        let handled = false;

                        try {
                            const parsed = JSON.parse(rawValue);
                            if (Array.isArray(parsed)) {
                                const validValues = parsed.filter(function(value) {
                                    return value !== null && value !== undefined && String(value).trim().length > 0;
                                });
                                total += validValues.length;
                                handled = true;
                            } else if (parsed !== null && typeof parsed !== 'object') {
                                if (String(parsed).trim().length > 0) {
                                    total += 1;
                                }
                                handled = true;
                            }
                        } catch (error) {
                            // continue with other parsing strategies
                        }

                        if (!handled) {
                            const metaAttr = control.attr('data-gf-file-meta');
                            if (metaAttr) {
                                try {
                                    const metaStore = JSON.parse(metaAttr);
                                    if (metaStore && typeof metaStore === 'object' && !Array.isArray(metaStore)) {
                                        total += Object.keys(metaStore).length;
                                        handled = true;
                                    }
                                } catch (error) {
                                    // ignore invalid JSON and continue
                                }
                            }
                        }

                        if (!handled) {
                            const parts = String(rawValue)
                                .split(',')
                                .map(function(value) {
                                    return value.trim();
                                })
                                .filter(function(value) {
                                    return value.length > 0;
                                });

                            if (parts.length > 0) {
                                total += parts.length;
                                handled = true;
                            }
                        }

                        if (!handled && String(rawValue).trim().length > 0) {
                            total += 1;
                        }

                        return;
                    }

                    if ('select' === tagName) {
                        const optionValue = control.val();

                        if (Array.isArray(optionValue)) {
                            const validValues = optionValue.filter(function(value) {
                                return value !== null && value !== undefined && String(value).trim().length > 0;
                            });
                            total += validValues.length;
                        } else if (optionValue !== null && optionValue !== undefined && String(optionValue).trim().length > 0) {
                            total += 1;
                        }

                        return;
                    }

                    const value = control.val();
                    if (value !== null && value !== undefined && String(value).trim().length > 0) {
                        total += 1;
                    }
                });

                return total;
            }

            function getFieldIterationData(fieldId) {
                const controls = getFieldControls(fieldId);
                if (!controls.length) {
                    return [];
                }

                const iterations = [];

                controls.each(function() {
                    const control = $(this);
                    const controlType = (control.attr('type') || '').toLowerCase();
                    const tagName = (control.prop('tagName') || '').toLowerCase();
                    const rawValue = control.val();
                    const trimmedValue = (rawValue === null || typeof rawValue === 'undefined')
                        ? ''
                        : String(rawValue).trim();

                    let values = [];

                    if (control.is('[data-gf-file-meta]')) {
                        const metaAttr = control.attr('data-gf-file-meta');
                        if (metaAttr) {
                            try {
                                const metaStore = JSON.parse(metaAttr);
                                if (metaStore && typeof metaStore === 'object' && !Array.isArray(metaStore)) {
                                    values = Object.keys(metaStore).map(function(token) {
                                        return String(token);
                                    });
                                }
                            } catch (error) {
                                // ignore invalid JSON and fall back to tokens derived from the input value
                            }
                        }

                        if (!values.length && trimmedValue.length) {
                            values = trimmedValue
                                .split(',')
                                .map(function(token) {
                                    return token.trim();
                                })
                                .filter(function(token) {
                                    return token.length > 0;
                                });
                        }
                    } else if ('hidden' === controlType) {
                        if (trimmedValue.length) {
                            let parsedValue = null;
                            try {
                                parsedValue = JSON.parse(trimmedValue);
                            } catch (error) {
                                parsedValue = null;
                            }

                            if (Array.isArray(parsedValue)) {
                                values = parsedValue
                                    .filter(function(value) {
                                        return value !== null && value !== undefined && String(value).trim().length > 0;
                                    })
                                    .map(function(value) {
                                        return String(value);
                                    });
                            } else if (parsedValue !== null && typeof parsedValue !== 'object') {
                                const parsedString = String(parsedValue).trim();
                                if (parsedString.length) {
                                    values = [parsedString];
                                }
                            } else if (trimmedValue.length) {
                                values = [trimmedValue];
                            }
                        }
                    } else if ('select' === tagName) {
                        const optionValue = control.val();

                        if (Array.isArray(optionValue)) {
                            values = optionValue
                                .filter(function(value) {
                                    return value !== null && value !== undefined && String(value).trim().length > 0;
                                })
                                .map(function(value) {
                                    return String(value);
                                });
                        } else if (optionValue !== null && optionValue !== undefined) {
                            const optionString = String(optionValue).trim();
                            if (optionString.length) {
                                values = [optionString];
                            }
                        }
                    } else {
                        if (trimmedValue.length) {
                            values = [trimmedValue];
                        }
                    }

                    const hasValue = values.some(function(value) {
                        return String(value).trim().length > 0;
                    });

                    iterations.push({
                        control: control,
                        values: values,
                        hasValue: hasValue
                    });
                });

                return iterations;
            }

            const RESOLVE_GUARD_LIMIT = 10;
        <?php
    }

    // Outputs JavaScript helpers that resolve dynamic references and expressions.
    protected function renderResolutionHelpersJs()
    {
        ?>
            function tryParseJsonCandidate(input) {
                if (typeof input !== 'string') {
                    return null;
                }

                const trimmed = input.trim();
                if (!trimmed.length) {
                    return null;
                }

                try {
                    return JSON.parse(trimmed);
                } catch (error) {
                    return null;
                }
            }

            function isPlainObject(candidate) {
                return Object.prototype.toString.call(candidate) === '[object Object]';
            }

            function isFiniteNumber(value) {
                if (typeof Number.isFinite === 'function') {
                    return Number.isFinite(value);
                }

                return isFinite(value);
            }

            function isIntegerNumber(value) {
                if (typeof Number.isInteger === 'function') {
                    return Number.isInteger(value);
                }

                return typeof value === 'number' && isFiniteNumber(value) && Math.floor(value) === value;
            }

            function toFiniteNumber(value) {
                if (typeof value === 'number' && isFiniteNumber(value)) {
                    return value;
                }

                if (typeof value === 'string') {
                    const trimmed = value.trim();
                    if (!trimmed.length) {
                        return null;
                    }

                    const parsed = Number(trimmed);
                    if (isFiniteNumber(parsed)) {
                        return parsed;
                    }
                }

                return null;
            }

            function evaluateMathExpression(expression) {
                if (typeof expression !== 'string') {
                    return null;
                }

                const condensed = expression.replace(/\s+/g, '');
                if (!condensed.length) {
                    return null;
                }

                if (!/^[0-9+\-*/().]+$/.test(condensed)) {
                    return null;
                }

                try {
                    const result = Function('"use strict"; return (' + condensed + ');')();
                    if (typeof result === 'number' && isFiniteNumber(result)) {
                        return result;
                    }
                } catch (error) {
                    return null;
                }

                return null;
            }

            function resolveExpression(expression, state) {
                if (typeof expression !== 'string') {
                    return expression;
                }

                const tokenPattern = /\{[^{}]*\}/g;
                let mutated = expression;
                let hasToken = false;

                mutated = expression.replace(tokenPattern, function(match) {
                    const parsed = tryParseJsonCandidate(match);
                    if (null === parsed) {
                        return match;
                    }

                    hasToken = true;

                    const resolved = resolveDynamicValue(parsed, {
                        visited: Array.isArray(state.visited) ? state.visited.slice() : [],
                        depth: state.depth + 1,
                        currentFieldKey: state.currentFieldKey,
                        purpose: state.purpose,
                        meta: state.meta
                    });

                    if (Array.isArray(resolved)) {
                        if (!resolved.length) {
                            return '';
                        }

                        const first = resolved[0];
                        const numericArrayValue = toFiniteNumber(first);
                        if (numericArrayValue !== null) {
                            return String(numericArrayValue);
                        }

                        return String(first);
                    }

                    const numericValue = toFiniteNumber(resolved);
                    if (numericValue !== null) {
                        return String(numericValue);
                    }

                    if (null === resolved || typeof resolved === 'undefined') {
                        return '';
                    }

                    return String(resolved);
                });

                if (!hasToken) {
                    const numericFallback = toFiniteNumber(expression);
                    if (numericFallback !== null) {
                        return numericFallback;
                    }

                    return expression;
                }

                if (state.meta && state.meta.abort) {
                    return '';
                }

                const evaluated = evaluateMathExpression(mutated);
                if (evaluated !== null) {
                    return evaluated;
                }

                return mutated.trim();
            }

            function resolveDynamicValue(input, context) {
                const baseState = context || {};
                const sharedMeta = (baseState.meta && typeof baseState.meta === 'object') ? baseState.meta : {};
                const state = {
                    visited: Array.isArray(baseState.visited) ? baseState.visited.slice() : [],
                    depth: typeof baseState.depth === 'number' ? baseState.depth : 0,
                    currentFieldKey: typeof baseState.currentFieldKey === 'string'
                        ? baseState.currentFieldKey
                        : (typeof baseState.currentFieldId !== 'undefined' && baseState.currentFieldId !== null
                            ? String(baseState.currentFieldId)
                            : null),
                    purpose: baseState.purpose || 'general',
                    meta: sharedMeta
                };

                if (state.meta && state.meta.abort) {
                    return '';
                }

                if (state.depth > RESOLVE_GUARD_LIMIT) {
                    console.warn('GriffinForms conditional logic: maximum resolution depth reached.', {
                        purpose: state.purpose,
                        chain: state.visited
                    });

                    state.meta.abort = true;
                    return '';
                }

                if (Array.isArray(input)) {
                    return input.map(function(item) {
                        if (state.meta && state.meta.abort) {
                            return '';
                        }

                        return resolveDynamicValue(item, {
                            visited: state.visited.slice(),
                            depth: state.depth + 1,
                            currentFieldKey: state.currentFieldKey,
                            purpose: state.purpose,
                            meta: state.meta
                        });
                    });
                }

                if (isPlainObject(input)) {
                    const referenceType = String(input.type || '').toLowerCase();

                    if ('field' === referenceType) {
                        const targetFieldKey = String(input.id || '').trim();

                        if (!targetFieldKey.length) {
                            console.warn('GriffinForms conditional logic: invalid field reference encountered.', input);
                            state.meta.abort = true;
                            return '';
                        }

                        if (state.currentFieldKey !== null && targetFieldKey === state.currentFieldKey) {
                            console.warn('GriffinForms conditional logic: prevented self-referential field lookup.', {
                                purpose: state.purpose,
                                field: targetFieldKey
                            });

                            state.meta.abort = true;
                            return '';
                        }

                        if (state.visited.includes(targetFieldKey)) {
                            const chain = state.visited.concat([targetFieldKey]);
                            console.warn('GriffinForms conditional logic: circular field reference detected.', {
                                purpose: state.purpose,
                                chain: chain
                            });

                            state.meta.abort = true;
                            return '';
                        }

                        const attributeRaw = Object.prototype.hasOwnProperty.call(input, 'attr')
                            ? String(input.attr).toLowerCase()
                            : 'value';
                        const attribute = attributeRaw.length ? attributeRaw : 'value';

                        if (!['value', 'iteration_count', 'value_count', 'product_name', 'product_quantity'].includes(attribute)) {
                            console.warn('GriffinForms conditional logic: unsupported field attribute reference.', input);
                            state.meta.abort = true;
                            return '';
                        }

                        if ('product_name' === attribute || 'product_quantity' === attribute) {
                            const cart = getPaymentCart(targetFieldKey);
                            const items = Array.isArray(cart.items) ? cart.items : [];
                            if ('product_name' === attribute) {
                                const names = items.map(function(item) {
                                    return String(item.product_name || item.name || item.product_id || item.id || '');
                                }).filter(function(n) { return n.length > 0; });
                                return names.join(', ');
                            }
                            // product_quantity: sum quantities across all selected products
                            const total = items.reduce(function(sum, item) {
                                const qty = parseFloat(item.quantity);
                                return sum + (isFinite(qty) ? qty : 0);
                            }, 0);
                            return String(total % 1 === 0 ? Math.round(total) : total);
                        }

                        let iterationIndex = null;
                        if (Object.prototype.hasOwnProperty.call(input, 'iteration')) {
                            const iterationCandidate = input.iteration;
                            let iterationValue = null;

                            if (typeof iterationCandidate === 'number') {
                                iterationValue = iterationCandidate;
                            } else if (typeof iterationCandidate === 'string') {
                                iterationValue = toFiniteNumber(iterationCandidate);
                            }

                            if (iterationValue === null || !isIntegerNumber(iterationValue)) {
                                console.warn('GriffinForms conditional logic: non-integer iteration requested.', input);
                                state.meta.abort = true;
                                return '';
                            }

                            if (iterationValue < 1) {
                                console.warn('GriffinForms conditional logic: iteration index must be 1 or greater.', input);
                                state.meta.abort = true;
                                return '';
                            }

                            iterationIndex = iterationValue - 1;
                        }

                        const nextVisited = state.visited.slice();
                        nextVisited.push(targetFieldKey);

                        if ('iteration_count' === attribute || 'value_count' === attribute) {
                            const iterationData = getFieldIterationData(targetFieldKey);

                            if (iterationIndex !== null) {
                                if (iterationIndex >= iterationData.length) {
                                    console.warn('GriffinForms conditional logic: requested iteration exceeds available values.', {
                                        purpose: state.purpose,
                                        field: targetFieldKey,
                                        iteration: iterationIndex + 1
                                    });
                                    state.meta.abort = true;
                                    return '';
                                }

                                const record = iterationData[iterationIndex] || null;

                                if ('iteration_count' === attribute) {
                                    return record && record.hasValue ? 1 : 0;
                                }

                                const count = record ? record.values.length : 0;
                                return count;
                            }

                            if ('iteration_count' === attribute) {
                                return iterationData.reduce(function(total, record) {
                                    return total + (record && record.hasValue ? 1 : 0);
                                }, 0);
                            }

                            return iterationData.reduce(function(total, record) {
                                if (!record) {
                                    return total;
                                }
                                return total + record.values.length;
                            }, 0);
                        }

                        const values = getFieldValues(targetFieldKey);
                        if (!values.length) {
                            return '';
                        }

                        if (iterationIndex !== null) {
                            if (iterationIndex >= values.length) {
                                console.warn('GriffinForms conditional logic: requested iteration exceeds available values.', {
                                    purpose: state.purpose,
                                    field: targetFieldKey,
                                    iteration: iterationIndex + 1
                                });
                                state.meta.abort = true;
                                return '';
                            }
                            return resolveDynamicValue(values[iterationIndex], {
                                visited: nextVisited,
                                depth: state.depth + 1,
                                currentFieldKey: state.currentFieldKey,
                                purpose: state.purpose,
                                meta: state.meta
                            });
                        }

                        // No iteration specified — join all values
                        return values.map(function(v) {
                            return String(resolveDynamicValue(v, {
                                visited: nextVisited.slice(),
                                depth: state.depth + 1,
                                currentFieldKey: state.currentFieldKey,
                                purpose: state.purpose,
                                meta: state.meta
                            }));
                        }).join(', ');
                    }

                    return input;
                }

                if (typeof input === 'string') {
                    const trimmed = input.trim();
                    if (!trimmed.length) {
                        return '';
                    }

                    const firstChar = trimmed.charAt(0);
                    const lastChar = trimmed.charAt(trimmed.length - 1);

                    if ((firstChar === '[' && lastChar === ']') ||
                        (firstChar === '"' && lastChar === '"') ||
                        (firstChar === '{' && lastChar === '}')) {
                        const parsed = tryParseJsonCandidate(trimmed);
                        if (parsed !== null) {
                            return resolveDynamicValue(parsed, {
                                visited: state.visited.slice(),
                                depth: state.depth + 1,
                                currentFieldKey: state.currentFieldKey,
                                purpose: state.purpose,
                                meta: state.meta
                            });
                        }
                    }

                    return resolveExpression(trimmed, state);
                }

                if (null === input || typeof input === 'undefined') {
                    return '';
                }

                return input;
            }

            function normalizeExpected(input, options) {
                const configuration = (options && typeof options === 'object') ? options : {};
                if (!configuration.meta || typeof configuration.meta !== 'object') {
                    configuration.meta = {};
                }

                const resolved = resolveDynamicValue(input, configuration);

                if (Array.isArray(resolved)) {
                    return resolved.map(function(item) {
                        return String(item);
                    });
                }

                if (null === resolved || typeof resolved === 'undefined') {
                    return '';
                }

                if (typeof resolved === 'number' && isFiniteNumber(resolved)) {
                    return String(resolved);
                }

                if (typeof resolved === 'boolean') {
                    return resolved ? 'true' : 'false';
                }

                if (typeof resolved === 'string') {
                    return resolved;
                }

                if (isPlainObject(resolved)) {
                    return '';
                }

                return String(resolved);
            }
        <?php
    }

    // Outputs JavaScript functions that evaluate conditional comparisons.
    protected function renderEvaluationHelpersJs()
    {
        ?>
            const ADDRESS_EVALUATORS = new Set([
                'line1_equals',
                'line1_contains',
                'line2_contains',
                'city_equals',
                'city_contains',
                'state_equals',
                'state_in_list',
                'postal_equals',
                'postal_starts_with',
                'country_equals',
                'country_in_list',
                'country_not_in_list',
                'address_is_complete',
                'address_is_not_complete'
            ]);

            const ADDRESS_LABEL_OPERATIONS = new Set([
                'change_line_1_label_to',
                'change_line_2_label_to',
                'change_city_label_to',
                'change_state_label_to',
                'change_country_label_to'
            ]);

            const PAYMENT_ATTRIBUTES = new Set([
                'selected_product',
                'product_quantity',
                'total_amount',
                'selection_count',
                'selected_gateway'
            ]);

            function compilePattern(pattern) {
                if (typeof pattern !== 'string') {
                    return null;
                }

                const trimmed = pattern.trim();
                if (!trimmed.length) {
                    return null;
                }

                let source = trimmed;
                let flags = '';

                if (source.charAt(0) === '/' && source.lastIndexOf('/') > 0) {
                    const lastSlash = source.lastIndexOf('/');
                    const candidateFlags = source.slice(lastSlash + 1);
                    source = source.slice(1, lastSlash);
                    flags = candidateFlags;
                }

                try {
                    return new RegExp(source, flags);
                } catch (error) {
                    return null;
                }
            }

            function getAddressPayloads(fieldId) {
                const controls = getFieldControls(fieldId);
                if (!controls.length) {
                    return [];
                }

                const payloads = [];
                controls.filter('[data-gf-address-json="1"]').each(function() {
                    const raw = $(this).val();
                    if (typeof raw !== 'string' || !raw.length) {
                        payloads.push({
                            line1: '',
                            line2: '',
                            city: '',
                            state: '',
                            state_upper: '',
                            postal: '',
                            country: '',
                            country_upper: ''
                        });
                        return;
                    }

                    try {
                        const parsed = JSON.parse(raw);
                        if (typeof parsed !== 'object' || parsed === null) {
                            return;
                        }

                        const payload = {
                            line1: String(parsed.line1 || '').trim(),
                            line2: String(parsed.line2 || '').trim(),
                            city: String(parsed.city || '').trim(),
                            state: String(parsed.state || '').trim(),
                            postal: String(parsed.postal || '').trim(),
                            country: String(parsed.country || '').trim()
                        };
                        payload.state_upper = payload.state.toUpperCase();
                        payload.country_upper = payload.country.toUpperCase();
                        payloads.push(payload);
                    } catch (error) {
                        // Ignore malformed JSON
                    }
                });

                return payloads;
            }

            function getPaymentCart(fieldId) {
                const controls = getFieldControls(fieldId);
                if (!controls.length) {
                    return { items: [], gateway: '' };
                }

                let payload = { items: [], gateway: '' };

                controls.filter('.griffinforms-payment-hidden').each(function() {
                    const raw = $(this).val();
                    if (typeof raw !== 'string' || !raw.length) {
                        return;
                    }
                    try {
                        const parsed = JSON.parse(raw);
                        if (parsed && typeof parsed === 'object') {
                            const items = Array.isArray(parsed.items) ? parsed.items : [];
                            const gateway = typeof parsed.gateway === 'string' ? parsed.gateway : '';
                            payload = { items: items, gateway: gateway };
                        }
                    } catch (error) {
                        // ignore malformed JSON
                    }
                });

                return payload;
            }

            function getPaymentTotals(cart) {
                const items = Array.isArray(cart.items) ? cart.items : [];
                let subtotal = 0;
                let quantitySum = 0;
                items.forEach(function(item) {
                    const qty = parseFloat(item.quantity) || 0;
                    const total = parseFloat(item.total) || 0;
                    quantitySum += qty;
                    subtotal += total;
                });
                return { subtotal: subtotal, quantity: quantitySum, count: items.length };
            }

            function evaluatePaymentCondition(fieldId, attribute, evaluator, expectedRaw) {
                const cart = getPaymentCart(fieldId);
                const { subtotal, quantity, count } = getPaymentTotals(cart);
                const ev = String(evaluator || '').toLowerCase();
                const attr = String(attribute || '').toLowerCase();

                if (attr === 'selected_product') {
                    const expected = String(coerceExpectedString(expectedRaw));
                    if (!expected.length) return false;
                    const hasProduct = (cart.items || []).some(function(item) {
                        return String(item.product_id || item.id || '').toLowerCase() === expected.toLowerCase();
                    });
                    if (ev === 'not_equal_to' || ev === 'not_contains' || ev === 'does_not_contain') {
                        return !hasProduct;
                    }
                    return hasProduct;
                }

                if (attr === 'selected_gateway') {
                    const expected = String(coerceExpectedString(expectedRaw)).toLowerCase();
                    const current = String(cart.gateway || '').toLowerCase();
                    if (!expected.length) return false;
                    if (ev === 'not_equal_to') {
                        return current !== expected;
                    }
                    return current === expected;
                }

                let target = Number(normalizeExpected(expectedRaw, { purpose: 'condition' }));
                if (!isFinite(target)) {
                    return false;
                }

                let actual = 0;
                if (attr === 'product_quantity') {
                    actual = quantity;
                } else if (attr === 'total_amount') {
                    actual = subtotal;
                } else if (attr === 'selection_count') {
                    actual = count;
                } else {
                    return false;
                }

                switch (ev) {
                    case 'less_than':
                        return actual < target;
                    case 'more_than':
                        return actual > target;
                    case 'equal_to':
                        return actual === target;
                    default:
                        return false;
                }
            }

            function isAddressComplete(addressPayload) {
                if (!addressPayload) {
                    return false;
                }

                return Boolean(
                    addressPayload.line1 &&
                    addressPayload.city &&
                    addressPayload.postal &&
                    addressPayload.country
                );
            }

            function normalizeListInput(expected, transformer) {
                const queue = Array.isArray(expected) ? expected.slice() : [expected];
                const result = [];

                for (let i = 0; i < queue.length; i++) {
                    const item = queue[i];
                    if (Array.isArray(item)) {
                        queue.push.apply(queue, item);
                        continue;
                    }

                    if (item === null || typeof item === 'undefined') {
                        continue;
                    }

                    const text = String(item).trim();
                    if (!text.length) {
                        continue;
                    }

                    const segments = text.split(/[\n,]+/);
                    segments.forEach(function(segment) {
                        const trimmed = segment.trim();
                        if (!trimmed.length) {
                            return;
                        }

                        result.push(transformer ? transformer(trimmed) : trimmed);
                    });
                }

                return result;
            }

            function coerceExpectedString(expected) {
                if (Array.isArray(expected)) {
                    for (let i = 0; i < expected.length; i++) {
                        const entry = expected[i];
                        if (entry === null || typeof entry === 'undefined') {
                            continue;
                        }
                        const text = String(entry).trim();
                        if (text.length) {
                            return text;
                        }
                    }
                    return '';
                }

                if (expected === null || typeof expected === 'undefined') {
                    return '';
                }

                return String(expected).trim();
            }

            function evaluateValueCondition(fieldId, evaluator, expectedRaw) {
                const fieldKey = String(fieldId);
                const values = getFieldValues(fieldId).map(function(value) {
                    return value.trim();
                });

                const controls = getFieldControls(fieldId);
                if (!controls.length && !getFieldContainer(fieldId).length) {
                    return false;
                }

                const logicValueType = controls.length
                    ? (controls.first().attr('data-gf-logic-value-type') || '').toLowerCase()
                    : '';
                const logicDateFormat = controls.length
                    ? (controls.first().attr('data-gf-logic-date-format') || '')
                    : '';

                const resolverMeta = {};
                const expected = normalizeExpected(expectedRaw, {
                    currentFieldKey: fieldKey,
                    visited: [fieldKey],
                    purpose: 'condition',
                    meta: resolverMeta
                });
                if (resolverMeta.abort) {
                    return false;
                }
                const hasValue = values.some(function(value) {
                    return value.length > 0;
                });

                const numericValues = ('date' === logicValueType)
                    ? values.map(function(value) {
                        return convertDateValueToTimestamp(value, logicDateFormat);
                    }).filter(function(timestamp) {
                        return timestamp !== null;
                    })
                    : [];

                const evaluatorKey = String(evaluator || '').toLowerCase();

                if (ADDRESS_EVALUATORS.has(evaluatorKey)) {
                    const addressPayloads = getAddressPayloads(fieldId);

                    if (evaluatorKey === 'address_is_not_complete') {
                        if (!addressPayloads.length) {
                            return true;
                        }

                        return addressPayloads.some(function(payload) {
                            return !isAddressComplete(payload);
                        });
                    }

                    if (!addressPayloads.length) {
                        return false;
                    }

                    switch (evaluatorKey) {
                        case 'address_is_complete':
                            return addressPayloads.some(function(payload) {
                                return isAddressComplete(payload);
                            });

                        case 'line1_equals': {
                            const target = coerceExpectedString(expected);
                            if (!target.length) {
                                return false;
                            }
                            const targetLower = target.toLowerCase();
                            return addressPayloads.some(function(payload) {
                                return payload.line1.toLowerCase() === targetLower;
                            });
                        }

                        case 'line1_contains': {
                            const needle = coerceExpectedString(expected);
                            if (!needle.length) {
                                return false;
                            }
                            const needleLower = needle.toLowerCase();
                            return addressPayloads.some(function(payload) {
                                return payload.line1.toLowerCase().indexOf(needleLower) !== -1;
                            });
                        }

                        case 'line2_contains': {
                            const needle = coerceExpectedString(expected);
                            if (!needle.length) {
                                return false;
                            }
                            const needleLower = needle.toLowerCase();
                            return addressPayloads.some(function(payload) {
                                return payload.line2.toLowerCase().indexOf(needleLower) !== -1;
                            });
                        }

                        case 'city_equals': {
                            const target = coerceExpectedString(expected);
                            if (!target.length) {
                                return false;
                            }
                            const targetLower = target.toLowerCase();
                            return addressPayloads.some(function(payload) {
                                return payload.city.toLowerCase() === targetLower;
                            });
                        }

                        case 'city_contains': {
                            const needle = coerceExpectedString(expected);
                            if (!needle.length) {
                                return false;
                            }
                            const needleLower = needle.toLowerCase();
                            return addressPayloads.some(function(payload) {
                                return payload.city.toLowerCase().indexOf(needleLower) !== -1;
                            });
                        }

                        case 'state_equals': {
                            const target = coerceExpectedString(expected).toUpperCase();
                            if (!target.length) {
                                return false;
                            }
                            return addressPayloads.some(function(payload) {
                                return payload.state_upper === target;
                            });
                        }

                        case 'state_in_list': {
                            const stateList = normalizeListInput(expected, function(entry) {
                                return entry.toUpperCase();
                            });
                            if (!stateList.length) {
                                return false;
                            }
                            return addressPayloads.some(function(payload) {
                                return payload.state_upper.length && stateList.includes(payload.state_upper);
                            });
                        }

                        case 'postal_equals': {
                            const target = coerceExpectedString(expected).toUpperCase();
                            if (!target.length) {
                                return false;
                            }
                            return addressPayloads.some(function(payload) {
                                return payload.postal.toUpperCase() === target;
                            });
                        }

                        case 'postal_starts_with': {
                            const needle = coerceExpectedString(expected).toUpperCase();
                            if (!needle.length) {
                                return false;
                            }
                            return addressPayloads.some(function(payload) {
                                return payload.postal.toUpperCase().startsWith(needle);
                            });
                        }

                        case 'country_equals': {
                            const target = coerceExpectedString(expected).toUpperCase();
                            if (!target.length) {
                                return false;
                            }
                            return addressPayloads.some(function(payload) {
                                return payload.country_upper === target;
                            });
                        }

                        case 'country_in_list': {
                            const countries = normalizeListInput(expected, function(entry) {
                                return entry.toUpperCase();
                            });
                            if (!countries.length) {
                                return false;
                            }
                            return addressPayloads.some(function(payload) {
                                return payload.country_upper.length && countries.includes(payload.country_upper);
                            });
                        }

                        case 'country_not_in_list': {
                            const countries = normalizeListInput(expected, function(entry) {
                                return entry.toUpperCase();
                            });
                            if (!countries.length) {
                                return false;
                            }
                            return addressPayloads.every(function(payload) {
                                return !payload.country_upper.length || !countries.includes(payload.country_upper);
                            });
                        }
                    }

                    return false;
                }

                const termsValueIsAccepted = function(rawValue) {
                    if (rawValue === 1) {
                        return true;
                    }

                    if (typeof rawValue !== 'string') {
                        return false;
                    }

                    const normalized = rawValue.trim().toLowerCase();
                    return normalized === '1' || normalized === 'accepted' || normalized === 'true';
                };

                switch (evaluatorKey) {
                    case 'is_checked':
                        return values.some(function(value) {
                            return value.length > 0;
                        });

                    case 'is_not_checked':
                        return values.every(function(value) {
                            return value.length === 0;
                        });

                    case 'is_accepted':
                        return values.some(function(value) {
                            return termsValueIsAccepted(value);
                        });

                    case 'is_not_accepted':
                        return values.every(function(value) {
                            return !termsValueIsAccepted(value);
                        });

                    case 'match_pattern':
                    case 'matches_pattern':
                        if (typeof expected !== 'string' || !expected.length) {
                            return false;
                        }

                        const regex = compilePattern(expected);
                        if (!regex) {
                            return false;
                        }

                        return values.some(function(value) {
                            regex.lastIndex = 0;
                            return regex.test(value);
                        });
                    case 'not_match_pattern':
                    case 'not_matches_pattern':
                        if (typeof expected !== 'string' || !expected.length) {
                            return false;
                        }

                        const inversePattern = compilePattern(expected);
                        if (!inversePattern) {
                            return false;
                        }

                        return values.every(function(value) {
                            inversePattern.lastIndex = 0;
                            return !inversePattern.test(value);
                        });
                }

                switch (evaluatorKey) {
                    case 'equal_to':
                        if (Array.isArray(expected)) {
                            if (!expected.length && !hasValue) {
                                return true;
                            }

                            return expected.every(function(target) {
                                return values.includes(target);
                            }) && values.every(function(value) {
                                return expected.includes(value);
                            });
                        }

                        if (!String(expected).length) {
                            return false;
                        }

                        return values.some(function(value) {
                            return value === String(expected);
                        });

                    case 'not_equal_to':
                        if (Array.isArray(expected)) {
                            if (!expected.length) {
                                return hasValue;
                            }

                            const allMatch = expected.every(function(target) {
                                return values.includes(target);
                            }) && values.every(function(value) {
                                return expected.includes(value);
                            });

                            return !allMatch;
                        }

                        if (!String(expected).length) {
                            return hasValue;
                        }

                        return values.every(function(value) {
                            return value !== String(expected);
                        });

                    case 'contains':
                        if (Array.isArray(expected)) {
                            if (!expected.length) {
                                return false;
                            }

                            return expected.every(function(target) {
                                return values.some(function(value) {
                                    return value.indexOf(target) !== -1;
                                });
                            });
                        }

                        if (!String(expected).length) {
                            return false;
                        }

                        return values.some(function(value) {
                            return value.indexOf(String(expected)) !== -1;
                        });

                    case 'not_contains':
                    case 'does_not_contain':
                        if (Array.isArray(expected)) {
                            if (!expected.length) {
                                return true;
                            }

                            return expected.every(function(target) {
                                return values.every(function(value) {
                                    return value.indexOf(target) === -1;
                                });
                            });
                        }

                        if (!String(expected).length) {
                            return true;
                        }

                        return values.every(function(value) {
                            return value.indexOf(String(expected)) === -1;
                        });

                    case 'starts_with':
                        if (Array.isArray(expected)) {
                            if (!expected.length) {
                                return false;
                            }

                            return expected.every(function(target) {
                                return values.some(function(value) {
                                    return value.startsWith(target);
                                });
                            });
                        }

                        if (!String(expected).length) {
                            return false;
                        }

                        return values.some(function(value) {
                            return value.startsWith(String(expected));
                        });

                    case 'ends_with':
                        if (Array.isArray(expected)) {
                            if (!expected.length) {
                                return false;
                            }

                            return expected.every(function(target) {
                                return values.some(function(value) {
                                    return value.endsWith(target);
                                });
                            });
                        }

                        if (!String(expected).length) {
                            return false;
                        }

                        return values.some(function(value) {
                            return value.endsWith(String(expected));
                        });

                    case 'before':
                        if ('date' !== logicValueType) {
                            return false;
                        }

                        const beforeTargetSource = Array.isArray(expected) ? expected[0] : expected;
                        const beforeTarget = convertDateValueToTimestamp(beforeTargetSource, logicDateFormat);
                        if (beforeTarget === null) {
                            return false;
                        }

                        return numericValues.some(function(value) {
                            return value < beforeTarget;
                        });

                    case 'after':
                        if ('date' !== logicValueType) {
                            return false;
                        }

                        const afterTargetSource = Array.isArray(expected) ? expected[0] : expected;
                        const afterTarget = convertDateValueToTimestamp(afterTargetSource, logicDateFormat);
                        if (afterTarget === null) {
                            return false;
                        }

                        return numericValues.some(function(value) {
                            return value > afterTarget;
                        });

                    case 'earlier_than':
                        if ('time' !== logicValueType) {
                            return false;
                        }

                        const earlierThanTarget = Array.isArray(expected) ? expected[0] : expected;
                        if (!earlierThanTarget || earlierThanTarget === '') {
                            return false;
                        }

                        return values.some(function(value) {
                            // Compare time strings directly (HH:MM format)
                            return value < earlierThanTarget;
                        });

                    case 'later_than':
                        if ('time' !== logicValueType) {
                            return false;
                        }

                        const laterThanTarget = Array.isArray(expected) ? expected[0] : expected;
                        if (!laterThanTarget || laterThanTarget === '') {
                            return false;
                        }

                        return values.some(function(value) {
                            // Compare time strings directly (HH:MM format)
                            return value > laterThanTarget;
                        });

                    case 'is_signed':
                        return values.some(function(value) {
                            return value.length > 0;
                        });

                    case 'is_not_signed':
                        return values.every(function(value) {
                            return value.length === 0;
                        });

                    case 'is_empty':
                        return !hasValue;

                    case 'is_not_empty':
                        return hasValue;

                    case 'greater_than': {
                        const gtTarget = parseFloat(Array.isArray(expected) ? expected[0] : expected);
                        if (isNaN(gtTarget)) { return false; }
                        return values.some(function(value) {
                            return parseFloat(value) > gtTarget;
                        });
                    }

                    case 'less_than': {
                        const ltTarget = parseFloat(Array.isArray(expected) ? expected[0] : expected);
                        if (isNaN(ltTarget)) { return false; }
                        return values.some(function(value) {
                            return parseFloat(value) < ltTarget;
                        });
                    }

                    case 'greater_than_or_equal': {
                        const gteTarget = parseFloat(Array.isArray(expected) ? expected[0] : expected);
                        if (isNaN(gteTarget)) { return false; }
                        return values.some(function(value) {
                            return parseFloat(value) >= gteTarget;
                        });
                    }

                    case 'less_than_or_equal': {
                        const lteTarget = parseFloat(Array.isArray(expected) ? expected[0] : expected);
                        if (isNaN(lteTarget)) { return false; }
                        return values.some(function(value) {
                            return parseFloat(value) <= lteTarget;
                        });
                    }

                    case 'is_complete':
                    case 'is_not_complete':
                    case 'row_answer_is':
                    case 'row_answer_is_not': {
                        const likertWrap = $('[data-gf-likert-field="' + fieldKey + '"]');
                        if (!likertWrap.length) {
                            return false;
                        }
                        const hiddenInput = likertWrap.find('[data-gf-likert-hidden]');
                        if (!hiddenInput.length) {
                            return false;
                        }
                        const rawJson = (hiddenInput.val() || '').trim();
                        let responses = {};
                        if (rawJson.length) {
                            try { responses = JSON.parse(rawJson); } catch (e) { responses = {}; }
                        }
                        if (!responses || typeof responses !== 'object' || Array.isArray(responses)) {
                            responses = {};
                        }

                        if (evaluatorKey === 'is_complete') {
                            const rowEls = likertWrap.find('tr[data-gf-likert-row]');
                            if (!rowEls.length) {
                                return false;
                            }
                            let allAnswered = true;
                            rowEls.each(function() {
                                const rid = ($(this).attr('data-gf-likert-row') || '').toString();
                                if (!rid.length) { return; }
                                const val = responses[rid];
                                if (typeof val !== 'string' || !val.length) {
                                    allAnswered = false;
                                }
                            });
                            return allAnswered;
                        }

                        if (evaluatorKey === 'is_not_complete') {
                            const rowEls2 = likertWrap.find('tr[data-gf-likert-row]');
                            if (!rowEls2.length) {
                                return true;
                            }
                            let anyUnanswered = false;
                            rowEls2.each(function() {
                                const rid = ($(this).attr('data-gf-likert-row') || '').toString();
                                if (!rid.length) { return; }
                                const val = responses[rid];
                                if (typeof val !== 'string' || !val.length) {
                                    anyUnanswered = true;
                                }
                            });
                            return anyUnanswered;
                        }

                        if (evaluatorKey === 'row_answer_is' || evaluatorKey === 'row_answer_is_not') {
                            let targetRowId = '';
                            let targetColId = '';
                            const rawExpected = Array.isArray(expected) ? expected[0] : expected;
                            if (rawExpected && typeof rawExpected === 'string') {
                                try {
                                    const parsed = JSON.parse(rawExpected);
                                    if (parsed && typeof parsed === 'object') {
                                        targetRowId = (parsed.row_id || '').toString();
                                        targetColId = (parsed.col_id || '').toString();
                                    }
                                } catch (e) {}
                            }
                            if (!targetRowId.length || !targetColId.length) {
                                return false;
                            }
                            const actualVal = (responses[targetRowId] || '').toString();
                            const matches = actualVal === targetColId;
                            return evaluatorKey === 'row_answer_is' ? matches : !matches;
                        }

                        return false;
                    }

                    default:
                        return false;
                }
            }

            function getPasswordStrengthValues(fieldId) {
                const controls = getFieldControls(fieldId);
                if (!controls.length) {
                    return [];
                }

                const strengths = [];

                controls.each(function() {
                    const control = $(this);
                    const type = (control.attr('type') || '').toLowerCase();
                    if ('hidden' !== type) {
                        return;
                    }

                    const rawValue = control.val();
                    if (rawValue === null || typeof rawValue === 'undefined') {
                        return;
                    }

                    const textValue = String(rawValue);
                    if (!textValue.length) {
                        return;
                    }

                    let parsed = null;
                    try {
                        parsed = JSON.parse(textValue);
                    } catch (error) {
                        parsed = null;
                    }

                    if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
                        const passwordValue = typeof parsed.password === 'string' ? parsed.password : '';
                        if (passwordValue.length) {
                            strengths.push(determinePasswordStrength(passwordValue));
                        }
                        return;
                    }
                });

                return strengths;
            }

            function determinePasswordStrength(value) {
                if (typeof value !== 'string') {
                    return 'weak';
                }

                const length = value.length;
                if (!length) {
                    return 'weak';
                }

                const hasUpper = /[A-Z]/.test(value);
                const hasLower = /[a-z]/.test(value);
                const hasNumber = /[0-9]/.test(value);
                const hasSymbolOrSpace = /[^A-Za-z0-9]/.test(value) || /\s/.test(value);

                let classCount = 0;
                classCount += hasUpper ? 1 : 0;
                classCount += hasLower ? 1 : 0;
                classCount += hasNumber ? 1 : 0;
                classCount += hasSymbolOrSpace ? 1 : 0;

                if (length < 8 || classCount === 0) {
                    return 'weak';
                }

                if (classCount >= 3 && length >= 12) {
                    return 'very_strong';
                }

                if ((classCount >= 3 && length >= 10) || (classCount >= 2 && length >= 14)) {
                    return 'strong';
                }

                if (classCount >= 2 && length >= 8) {
                    return 'medium';
                }

                return 'weak';
            }

            function evaluateStrengthCondition(fieldId, evaluator) {
                const fieldKey = String(fieldId || '');
                if (!fieldKey.length) {
                    return false;
                }

                const evaluatorKey = String(evaluator || '').toLowerCase();
                if (!evaluatorKey.length) {
                    return false;
                }

                const strengths = getPasswordStrengthValues(fieldKey);
                if (!strengths.length) {
                    return false;
                }

                return strengths.some(function(strength) {
                    return strength === evaluatorKey;
                });
            }

            function evaluateCondition(condition) {
                if (!condition || typeof condition !== 'object') {
                    return false;
                }

                const itemType = String(condition.item || '').toLowerCase();
                const attribute = String(condition.attribute || '').toLowerCase();

                if ('user' === itemType && 'browser_time' === attribute) {
                    return evaluateUserTimeCondition(condition.evaluator, condition.input);
                }

                if ('field' === itemType && 'value' === attribute) {
                    return evaluateValueCondition(condition.item_id, condition.evaluator, condition.input);
                }

                if ('field' === itemType && PAYMENT_ATTRIBUTES.has(attribute)) {
                    return evaluatePaymentCondition(condition.item_id, attribute, condition.evaluator, condition.input);
                }

                if ('field' === itemType && 'attribute_count' === attribute) {
                    return evaluateCountCondition(condition.item_id, condition.evaluator, condition.input);
                }

                if ('field' === itemType && 'strength' === attribute) {
                    return evaluateStrengthCondition(condition.item_id, condition.evaluator);
                }

                return false;
            }

            function getUserLocalMinutesOfDay() {
                const now = new Date();
                return now.getHours() * 60 + now.getMinutes();
            }

            function parseMinutes(input) {
                if (typeof input === 'number' && isFiniteNumber(input)) return Math.floor(input);
                const n = Number(String(input).trim());
                if (isFiniteNumber(n)) return Math.floor(n);
                return null;
            }

            function evaluateUserTimeCondition(evaluator, expectedRaw) {
                const nowMinutes = getUserLocalMinutesOfDay();
                const target = parseMinutes(expectedRaw);
                if (target === null) return false;
                const ev = String(evaluator || '').toLowerCase();
                if (ev === 'before') return nowMinutes < target;
                if (ev === 'after') return nowMinutes > target;
                return false;
            }

            function evaluateCountCondition(fieldId, evaluator, expectedRaw) {
                const fieldKey = String(fieldId);
                const count = getFieldValueCount(fieldId);
                const resolverMeta = {};
                const normalized = normalizeExpected(expectedRaw, {
                    currentFieldKey: fieldKey,
                    visited: [fieldKey],
                    purpose: 'condition',
                    meta: resolverMeta
                });
                if (resolverMeta.abort) {
                    return false;
                }
                const target = Number(normalized);

                if (!isFinite(target)) {
                    return false;
                }

                switch (String(evaluator || '').toLowerCase()) {
                    case 'less_than':
                        return count < target;
                    case 'more_than':
                        return count > target;
                    case 'equal_to':
                        return count === target;
                    default:
                        return false;
                }
            }
        <?php
    }

    // Outputs JavaScript helpers that perform action side-effects on the form.
    protected function renderActionHelpersJs()
    {
        ?>
            function normalizeClassList(value) {
                if (Array.isArray(value)) {
                    value = value.join(' ');
                } else if (value === null || typeof value === 'undefined') {
                    value = '';
                }

                const source = value.toString().trim();
                if (!source.length) {
                    return [];
                }

                const cleaned = source
                    .replace(/[\r\n]+/g, ' ')
                    .replace(/,/g, ' ')
                    .split(/\s+/);

                const seen = {};
                const classes = [];

                cleaned.forEach(function (token) {
                    if (!token) {
                        return;
                    }
                    const stripped = token.replace(/^\.+/, '').replace(/[^A-Za-z0-9_-]/g, '');
                    if (!stripped.length || seen[stripped]) {
                        return;
                    }
                    seen[stripped] = true;
                    classes.push(stripped);
                });

                return classes;
            }

            function applyClassList(targets, classes, method) {
                if (!Array.isArray(classes) || !classes.length || !targets.length) {
                    return;
                }
                targets[method](classes.join(' '));
            }

            function resolveActionMessagePayload(payload, context) {
                const settings = (context && typeof context === 'object') ? context : {};
                const resolverMeta = {};
                const normalized = normalizeExpected(payload, {
                    currentFieldKey: typeof settings.currentFieldKey === 'string' ? settings.currentFieldKey : '',
                    visited: Array.isArray(settings.visited) ? settings.visited.slice() : [],
                    purpose: 'action',
                    meta: resolverMeta
                });

                if (resolverMeta.abort) {
                    return '';
                }

                if (Array.isArray(normalized)) {
                    return normalized.map(function(item) {
                        if (item === null || typeof item === 'undefined') {
                            return '';
                        }
                        return String(item);
                    }).join(', ');
                }

                if (null === normalized || typeof normalized === 'undefined') {
                    return '';
                }

                return String(normalized);
            }

            const MESSAGE_OPERATION_MAP = {
                show_error: { type: 'error', alertClass: 'alert-danger' },
                show_warning: { type: 'warning', alertClass: 'alert-warning' },
                show_info: { type: 'info', alertClass: 'alert-info' }
            };

            function setAlertContent(element, message) {
                if (!element || !element.length) {
                    return;
                }

                const content = (message === null || typeof message === 'undefined')
                    ? ''
                    : String(message);

                element.empty();

                if (!content.length) {
                    return;
                }

                const lines = content.split(/\r?\n/);
                lines.forEach(function(line, index) {
                    if (index) {
                        element.append(document.createElement('br'));
                    }
                    element.append(document.createTextNode(line));
                });
            }

            const FORM_POPUP_STATE = {};
            const SUCCESS_MESSAGE_STATE = {
                changeTo: [],
                append: []
            };
            const FIELD_STATE_TRACKER = {};
            const FIELD_OPTION_GROUP_STATE = {};
            const FORM_REDIRECT_STATE = {
                changeTo: {},
                append: {}
            };
            const FORM_SUBMIT_LABEL_STATE = {
                changeTo: []
            };
            const FORM_SUBMIT_STATE = {
                disable: {},
                enable: {},
                originalCaptured: false
            };
            let successMessageOriginalHtml = null;

            function getSuccessMessageContainer() {
                return $('.griffinforms-form' + formId + '-success_message');
            }

            function cacheOriginalSuccessMessage(container) {
                if (null === successMessageOriginalHtml && container && container.length) {
                    successMessageOriginalHtml = container.html();
                }
            }

            function setSuccessMessageStateEntry(type, key, text) {
                const list = SUCCESS_MESSAGE_STATE[type];
                if (!Array.isArray(list)) {
                    return;
                }

                const resolvedKey = String(key || '');
                if (!resolvedKey.length) {
                    return;
                }

                const existingIndex = list.findIndex(function(entry) {
                    return entry && entry.key === resolvedKey;
                });

                if (!text.length) {
                    if (existingIndex !== -1) {
                        list.splice(existingIndex, 1);
                    }
                    return;
                }

                if (existingIndex !== -1) {
                    list[existingIndex].text = text;
                    return;
                }

                list.push({
                    key: resolvedKey,
                    text: text
                });
            }

            function removeSuccessMessageStateEntry(type, key) {
                const list = SUCCESS_MESSAGE_STATE[type];
                if (!Array.isArray(list)) {
                    return;
                }

                const resolvedKey = String(key || '');
                if (!resolvedKey.length) {
                    return;
                }

                const existingIndex = list.findIndex(function(entry) {
                    return entry && entry.key === resolvedKey;
                });

                if (existingIndex !== -1) {
                    list.splice(existingIndex, 1);
                }
            }

            function createSuccessMessageNodes(message, options) {
                const normalized = (message === null || typeof message === 'undefined')
                    ? ''
                    : String(message).replace(/\r\n/g, '\n');

                if (!normalized.length) {
                    return [];
                }

                const lines = normalized.split('\n');
                const nodes = [];

                lines.forEach(function(line, index) {
                    if (index) {
                        nodes.push(document.createElement('br'));
                    }
                    nodes.push(document.createTextNode(line));
                });

                if (options && options.wrapTag) {
                    const wrapper = document.createElement(options.wrapTag);
                    if (options.className) {
                        wrapper.className = options.className;
                    }
                    nodes.forEach(function(node) {
                        wrapper.appendChild(node);
                    });
                    return [wrapper];
                }

                return nodes;
            }

            function appendNodes(target, nodes) {
                if (!target || !target.length || !Array.isArray(nodes) || !nodes.length) {
                    return;
                }

                nodes.forEach(function(node) {
                    target.append(node);
                });
            }

            function refreshSuccessMessage() {
                const container = getSuccessMessageContainer();
                if (!container.length) {
                    return;
                }

                cacheOriginalSuccessMessage(container);

                const changeEntries = SUCCESS_MESSAGE_STATE.changeTo;
                const hasChange = Array.isArray(changeEntries) && changeEntries.length > 0;

                if (hasChange) {
                    const lastEntry = changeEntries[changeEntries.length - 1];
                    container.empty();
                    appendNodes(container, createSuccessMessageNodes(lastEntry.text, { wrapTag: 'strong' }));
                } else if (null !== successMessageOriginalHtml) {
                    container.html(successMessageOriginalHtml);
                }

                container.find('.griffinforms-success-message-append').remove();

                const appendEntries = SUCCESS_MESSAGE_STATE.append;
                if (Array.isArray(appendEntries) && appendEntries.length) {
                    appendEntries.forEach(function(entry) {
                        if (!entry || !entry.text || !entry.text.length) {
                            return;
                        }

                        const span = $('<span/>', {
                            'class': 'griffinforms-success-message-append',
                            'data-gf-message-key': entry.key
                        });

                        if (container.contents().length) {
                            span.append(document.createTextNode(' '));
                        }

                        appendNodes(span, createSuccessMessageNodes(entry.text));
                        container.append(span);
                    });
                }
            }

            function hasStateEntries(store) {
                if (!store || typeof store !== 'object') {
                    return false;
                }

                for (var key in store) {
                    if (Object.prototype.hasOwnProperty.call(store, key)) {
                        return true;
                    }
                }

                return false;
            }

            function ensureFieldStateEntry(fieldId) {
                const fieldKey = String(fieldId);
                if (!Object.prototype.hasOwnProperty.call(FIELD_STATE_TRACKER, fieldKey)) {
                    FIELD_STATE_TRACKER[fieldKey] = {
                        disable: {},
                        enable: {},
                        originalDisabledCaptured: false,
                        originalDisabled: false
                    };
                }

                return FIELD_STATE_TRACKER[fieldKey];
            }

            function getFieldInteractiveContext(fieldId, entry) {
                const container = getFieldContainer(fieldId);
                if (!container.length) {
                    return {
                        container: container,
                        interactive: $()
                    };
                }

                const interactive = container.find('input, select, textarea, button');

                interactive.each(function() {
                    const element = $(this);
                    const defaultState = (entry && entry.originalDisabledCaptured)
                        ? entry.originalDisabled
                        : element.is(':disabled');

                    if (typeof element.data('gfOriginalDisabled') === 'undefined') {
                        element.data('gfOriginalDisabled', defaultState);
                    }
                });

                if (entry && !entry.originalDisabledCaptured) {
                    if (interactive.length) {
                        const allDisabled = interactive.toArray().every(function(node) {
                            return $(node).data('gfOriginalDisabled') === true;
                        });
                        entry.originalDisabled = allDisabled;
                    } else {
                        entry.originalDisabled = false;
                    }
                    entry.originalDisabledCaptured = true;
                }

                return {
                    container: container,
                    interactive: interactive
                };
            }

            function updateFieldDisabledState(fieldId) {
                const entry = ensureFieldStateEntry(fieldId);
                const context = getFieldInteractiveContext(fieldId, entry);
                const container = context.container;

                if (!container.length) {
                    return;
                }

                const interactive = context.interactive;
                const hasEnableOverride = hasStateEntries(entry.enable);
                const hasDisableOverride = hasStateEntries(entry.disable);

                let shouldDisable;

                if (hasEnableOverride) {
                    shouldDisable = false;
                } else if (hasDisableOverride) {
                    shouldDisable = true;
                } else {
                    shouldDisable = entry.originalDisabled;
                }

                container.toggleClass('griffinforms-field-disabled', shouldDisable);
                container.attr('aria-disabled', shouldDisable ? 'true' : 'false');

                if (!interactive.length) {
                    return;
                }

                interactive.each(function() {
                    const element = $(this);
                    const originalDisabled = element.data('gfOriginalDisabled') === true;

                    if (hasEnableOverride) {
                        element.prop('disabled', false).removeAttr('disabled');
                        return;
                    }

                    if (hasDisableOverride) {
                        element.prop('disabled', true).attr('disabled', 'disabled');
                        return;
                    }

                    if (originalDisabled) {
                        element.prop('disabled', true).attr('disabled', 'disabled');
                    } else {
                        element.prop('disabled', false).removeAttr('disabled');
                    }
                });
            }

            function ensureFieldOptionGroupsState(fieldId) {
                const fieldKey = String(fieldId);
                if (!Object.prototype.hasOwnProperty.call(FIELD_OPTION_GROUP_STATE, fieldKey)) {
                    FIELD_OPTION_GROUP_STATE[fieldKey] = {};
                }
                return FIELD_OPTION_GROUP_STATE[fieldKey];
            }

            function ensureOptionGroupStateEntry(fieldId, groupName) {
                const state = ensureFieldOptionGroupsState(fieldId);
                const normalizedName = String(groupName);
                if (!Object.prototype.hasOwnProperty.call(state, normalizedName)) {
                    state[normalizedName] = {
                        show: {},
                        hide: {}
                    };
                }
                return state[normalizedName];
            }

            function parseOptionGroupPayload(rawPayload) {
                if (Array.isArray(rawPayload)) {
                    const names = rawPayload
                        .map(function(entry) {
                            return String(entry).trim();
                        })
                        .filter(function(name) {
                            return name.length > 0;
                        });

                    return names.filter(function(name, index) {
                        return names.indexOf(name) === index;
                    });
                }

                if (rawPayload === null || typeof rawPayload === 'undefined') {
                    return [];
                }

                if (typeof rawPayload === 'string') {
                    const source = rawPayload.trim();
                    if (!source.length) {
                        return [];
                    }

                    try {
                        const decoded = JSON.parse(source);
                        if (Array.isArray(decoded)) {
                            return parseOptionGroupPayload(decoded);
                        }
                    } catch (err) {
                        // fall back to delimiter parsing
                    }

                    const parts = source.split(/[\n,]+/);
                    const cleaned = parts
                        .map(function(part) {
                            return part.trim();
                        })
                        .filter(function(part) {
                            return part.length > 0;
                        });

                    return cleaned.filter(function(name, index) {
                        return cleaned.indexOf(name) === index;
                    });
                }

                return [];
            }

            function collectOptionGroupElements(fieldId) {
                const controls = getFieldControls(fieldId);
                const groupsMap = {};

                controls.each(function() {
                    const control = $(this);
                    if (!control.is('select')) {
                        return;
                    }

                    control.children('optgroup').each(function() {
                        const optgroup = $(this);
                        const label = (optgroup.attr('label') || '').trim();
                        if (!label.length) {
                            return;
                        }

                        if (!groupsMap[label]) {
                            groupsMap[label] = {
                                groups: $(),
                                options: $()
                            };
                        }

                        groupsMap[label].groups = groupsMap[label].groups.add(optgroup);
                        groupsMap[label].options = groupsMap[label].options.add(optgroup.children('option'));
                    });
                });

                return groupsMap;
            }

            function refreshOptionGroupState(fieldId) {
                const state = ensureFieldOptionGroupsState(fieldId);
                const groupElements = collectOptionGroupElements(fieldId);
                const controls = getFieldControls(fieldId);

                Object.keys(groupElements).forEach(function(groupName) {
                    const elements = groupElements[groupName];
                    const entry = state[groupName] || { show: {}, hide: {} };
                    const hasHideOverride = hasStateEntries(entry.hide);
                    const shouldHide = hasHideOverride;

                    elements.groups.each(function() {
                        const optgroup = $(this);
                        if (shouldHide) {
                            optgroup.attr('data-gf-option-group-hidden', '1');
                            optgroup.prop('disabled', true);
                        } else {
                            optgroup.removeAttr('data-gf-option-group-hidden');
                            optgroup.prop('disabled', false);
                        }
                    });

                    elements.options.each(function() {
                        const option = $(this);
                        if (typeof option.data('gfOriginalDisabled') === 'undefined') {
                            option.data('gfOriginalDisabled', option.is(':disabled'));
                        }

                        const originalDisabled = option.data('gfOriginalDisabled') === true;

                        if (shouldHide) {
                            option.prop('disabled', true).attr('disabled', 'disabled').attr('hidden', 'hidden').addClass('d-none');
                        } else {
                            option.prop('disabled', originalDisabled);
                            if (!originalDisabled) {
                                option.removeAttr('disabled');
                            }
                            option.removeAttr('hidden').removeClass('d-none');
                        }
                    });
                });

                controls.each(function() {
                    const control = $(this);
                    if (!control.is('select')) {
                        return;
                    }

                    const selectedOption = control.find('option:selected');
                    if (selectedOption.length && (selectedOption.is(':disabled') || selectedOption.is('[hidden]') || selectedOption.hasClass('d-none'))) {
                        const fallback = control.find('option:not(:disabled):not([hidden]):not(.d-none)').first();
                        if (fallback.length) {
                            const fallbackValue = fallback.val();
                            if (control.val() !== fallbackValue) {
                                control.val(fallbackValue).trigger('change');
                            }
                        } else if (control.val() !== '') {
                            control.val('').trigger('change');
                        }
                    }
                });
            }

            function applySelectOptionGroups(fieldId, operation, payload, shouldApply, actionKey) {
                const op = String(operation || '').toLowerCase();
                if (op !== 'show' && op !== 'hide') {
                    return;
                }

                const parsedGroups = parseOptionGroupPayload(payload);
                const groupElements = collectOptionGroupElements(fieldId);
                const availableNames = Object.keys(groupElements);

                if (!availableNames.length) {
                    return;
                }

                const availableLookup = {};
                availableNames.forEach(function(name) {
                    availableLookup[name.toLowerCase()] = name;
                });

                const resolvedGroups = [];
                parsedGroups.forEach(function(name) {
                    const trimmed = String(name).trim();
                    if (!trimmed.length) {
                        return;
                    }
                    const actual = availableLookup[trimmed.toLowerCase()] || trimmed;
                    if (resolvedGroups.indexOf(actual) === -1) {
                        resolvedGroups.push(actual);
                    }
                });

                const state = ensureFieldOptionGroupsState(fieldId);
                const stateKey = String(actionKey || (op + '_' + fieldId));

                if ('show' === op) {
                    const selectedSet = {};
                    resolvedGroups.forEach(function(name) {
                        const actualName = availableLookup[name.toLowerCase()] || name;
                        if (availableNames.indexOf(actualName) !== -1) {
                            selectedSet[actualName] = true;
                        }
                    });

                    availableNames.forEach(function(name) {
                        const entry = ensureOptionGroupStateEntry(fieldId, name);
                        const isSelected = !!selectedSet[name];

                        if (shouldApply && isSelected) {
                            entry.show[stateKey] = true;
                            delete entry.hide[stateKey];
                        } else if (!shouldApply && isSelected) {
                            delete entry.show[stateKey];
                        } else if (shouldApply && !isSelected) {
                            entry.hide[stateKey] = true;
                            delete entry.show[stateKey];
                        } else if (!shouldApply && !isSelected) {
                            delete entry.hide[stateKey];
                        }

                        if (!hasStateEntries(entry.show) && !hasStateEntries(entry.hide)) {
                            delete state[name];
                        }
                    });
                } else {
                    resolvedGroups.forEach(function(name) {
                        const actualName = availableLookup[name.toLowerCase()] || name;
                        if (availableNames.indexOf(actualName) === -1) {
                            return;
                        }

                        const entry = ensureOptionGroupStateEntry(fieldId, actualName);

                        if (shouldApply) {
                            entry.hide[stateKey] = true;
                            delete entry.show[stateKey];
                        } else {
                            delete entry.hide[stateKey];
                        }

                        if (!hasStateEntries(entry.show) && !hasStateEntries(entry.hide)) {
                            delete state[actualName];
                        }
                    });
                }

                refreshOptionGroupState(fieldId);
            }

            function applyLikertRows(fieldId, operation, payload, shouldApply, actionKey) {
                const op = String(operation || '').toLowerCase();
                if (op !== 'show_rows' && op !== 'hide_rows') {
                    return;
                }

                const likertWrap = $('[data-gf-likert-field="' + String(fieldId) + '"]');
                if (!likertWrap.length) {
                    return;
                }

                let targetRowIds = [];
                const rawPayload = (typeof payload === 'string') ? payload.trim() : '';
                if (rawPayload.length) {
                    try {
                        const parsed = JSON.parse(rawPayload);
                        if (Array.isArray(parsed)) {
                            parsed.forEach(function(id) {
                                const s = String(id || '').trim();
                                if (s.length) {
                                    targetRowIds.push(s);
                                }
                            });
                        }
                    } catch (e) {}
                }

                const allRows = likertWrap.find('tr[data-gf-likert-row]');

                if (op === 'show_rows') {
                    allRows.each(function() {
                        const row = $(this);
                        const rid = (row.attr('data-gf-likert-row') || '').toString();
                        const inTarget = targetRowIds.indexOf(rid) !== -1;
                        if (shouldApply) {
                            if (inTarget) {
                                row.css('display', '');
                            } else {
                                clearLikertRowAnswer(row, fieldId, likertWrap);
                                row.css('display', 'none');
                            }
                        } else {
                            // Condition not met: hide the target rows (they should only appear when condition is met).
                            if (inTarget) {
                                clearLikertRowAnswer(row, fieldId, likertWrap);
                                row.css('display', 'none');
                            } else {
                                row.css('display', '');
                            }
                        }
                    });
                } else {
                    allRows.each(function() {
                        const row = $(this);
                        const rid = (row.attr('data-gf-likert-row') || '').toString();
                        const inTarget = targetRowIds.indexOf(rid) !== -1;
                        if (shouldApply && inTarget) {
                            clearLikertRowAnswer(row, fieldId, likertWrap);
                            row.css('display', 'none');
                        } else {
                            row.css('display', '');
                        }
                    });
                }
            }

            function clearLikertRowAnswer(rowEl, fieldId, likertWrap) {
                rowEl.find('input[type="radio"]').prop('checked', false);
                const hiddenInput = likertWrap.find('[data-gf-likert-hidden]');
                if (!hiddenInput.length) {
                    return;
                }
                const rawJson = (hiddenInput.val() || '').trim();
                let responses = {};
                if (rawJson.length) {
                    try { responses = JSON.parse(rawJson); } catch (e) { responses = {}; }
                }
                const rid = (rowEl.attr('data-gf-likert-row') || '').toString();
                if (rid.length && responses.hasOwnProperty(rid)) {
                    delete responses[rid];
                    hiddenInput.val(JSON.stringify(responses));
                }
            }

            function applyFormSuccessMessage(operation, payload, shouldApply, actionKey) {
                const container = getSuccessMessageContainer();
                if (!container.length) {
                    return;
                }

                cacheOriginalSuccessMessage(container);

                const op = String(operation || '').toLowerCase();
                const normalizedValue = resolveActionMessagePayload(payload, {
                    currentFieldKey: '',
                    visited: []
                }).replace(/\r\n/g, '\n');
                const normalized = normalizedValue.trim();

                if ('change_to' === op) {
                    if (shouldApply && normalized.length) {
                        setSuccessMessageStateEntry('changeTo', actionKey, normalizedValue);
                    } else {
                        removeSuccessMessageStateEntry('changeTo', actionKey);
                    }
                    refreshSuccessMessage();
                    return;
                }

                if ('append' === op) {
                    if (shouldApply && normalized.length) {
                        setSuccessMessageStateEntry('append', actionKey, normalizedValue);
                    } else {
                        removeSuccessMessageStateEntry('append', actionKey);
                    }
                    refreshSuccessMessage();
                }
            }

            function getFormContainer() {
                return $('.griffinforms-form' + formId + '-container');
            }

            function createLogicAlert(config, key) {
                return $('<div/>', {
                    'class': 'alert ' + config.alertClass + ' griffinforms-logic-alert mb-2',
                    'role': 'alert',
                    'data-gf-logic-message-key': key,
                    'data-gf-logic-message-type': config.type
                });
            }

            function toggleContainerMessage(container, config, messageText, key, shouldApply, insertCallback) {
                if (!container || !container.length) {
                    return;
                }

                const selector = '.griffinforms-logic-alert[data-gf-logic-message-key="' + key + '"]';
                let messageEl = container.find(selector).first();

                if (shouldApply && messageText.length) {
                    if (!messageEl.length) {
                        messageEl = createLogicAlert(config, key);
                        if (typeof insertCallback === 'function') {
                            const inserted = insertCallback(container, messageEl);
                            if (inserted && inserted.length) {
                                messageEl = inserted;
                            }
                        } else {
                            messageEl = messageEl.prependTo(container);
                        }
                    }

                    setAlertContent(messageEl, messageText);
                    messageEl.removeClass('d-none').show();
                    return;
                }

                if (messageEl.length) {
                    messageEl.remove();
                }
            }

            function toggleFieldMessage(fieldId, config, messageText, key, shouldApply) {
                const container = getFieldContainer(fieldId);
                if (!container.length) {
                    return;
                }

                toggleContainerMessage(
                    container,
                    config,
                    messageText,
                    key || (config.type + '_' + fieldId),
                    shouldApply,
                    function(parent, element) {
                        const label = parent.children('label.form-label').first();
                        if (label.length) {
                            element.insertAfter(label);
                            return element;
                        }
                        const firstControl = parent.find('.griffinforms-formcontrol-container').first();
                        if (firstControl.length) {
                            element.insertBefore(firstControl);
                            return element;
                        }
                        element.prependTo(parent);
                        return element;
                    }
                );
            }

            function toggleFormMessage(config, messageText, key, shouldApply) {
                const container = getFormContainer();
                if (!container.length) {
                    return;
                }

                toggleContainerMessage(
                    container,
                    config,
                    messageText,
                    key,
                    shouldApply,
                    function(parent, element) {
                        const header = parent.find('.griffinforms-form-header').first();
                        if (header.length) {
                            element.insertBefore(header);
                            return element;
                        }
                        element.prependTo(parent);
                        return element;
                    }
                );
            }

            function applyFieldVisibility(fieldId, operation, shouldApply, payload, actionKey) {
                const controls = getFieldControls(fieldId);
                if (!controls.length) {
                    return;
                }

                const op = String(operation || '').toLowerCase();
                const messageConfig = MESSAGE_OPERATION_MAP[op] || null;

                if (messageConfig) {
                    const resolvedKey = String(actionKey || messageConfig.type + '_' + fieldId);
                    const messageValue = resolveActionMessagePayload(payload, {
                        currentFieldKey: String(fieldId),
                        visited: [String(fieldId)]
                    });
                    const normalizedMessage = messageValue.replace(/\r\n/g, '\n');
                    const hasMessage = normalizedMessage.trim().length > 0;

                    if (shouldApply && !hasMessage) {
                        toggleFieldMessage(fieldId, messageConfig, '', resolvedKey, false);
                        return;
                    }

                    toggleFieldMessage(fieldId, messageConfig, normalizedMessage, resolvedKey, shouldApply);
                    return;
                }

                if (op === 'add_class' || op === 'remove_class') {
                    const classes = normalizeClassList(payload);
                    if (!classes.length && op === 'add_class' && !shouldApply) {
                        return;
                    }

                    if (op === 'add_class') {
                        if (shouldApply) {
                            applyClassList(controls, classes, 'addClass');
                        } else if (classes.length) {
                            controls.removeClass(classes.join(' '));
                        }
                        return;
                    }

                    if (shouldApply) {
                        applyClassList(controls, classes, 'removeClass');
                    }
                    return;
                }

                const container = controls.first().closest('.griffinforms-field-container');
                if (!container.length) {
                    return;
                }

                if ('show' === op) {
                    if (shouldApply) {
                        container.removeClass('d-none');
                    } else {
                        container.addClass('d-none');
                    }
                }

                if ('hide' === op) {
                    if (shouldApply) {
                        container.addClass('d-none');
                    } else {
                        container.removeClass('d-none');
                    }
                }
            }

            function applyRowVisibility(rowId, operation, shouldApply, payload) {
                const container = getRowContainer(rowId);
                if (!container.length) {
                    return;
                }

                const op = String(operation || '').toLowerCase();

                if (op === 'add_class' || op === 'remove_class') {
                    const classes = normalizeClassList(payload);
                    if (!classes.length && op === 'add_class' && !shouldApply) {
                        return;
                    }

                    if (op === 'add_class') {
                        if (shouldApply) {
                            applyClassList(container, classes, 'addClass');
                        } else if (classes.length) {
                            container.removeClass(classes.join(' '));
                        }
                        return;
                    }

                    if (shouldApply) {
                        applyClassList(container, classes, 'removeClass');
                    }
                    return;
                }

                if ('show' === op) {
                    if (shouldApply) {
                        container.removeClass('d-none');
                    } else {
                        container.addClass('d-none');
                    }
                }

                if ('hide' === op) {
                    if (shouldApply) {
                        container.addClass('d-none');
                    } else {
                        container.removeClass('d-none');
                    }
                }
            }

            function applyFormVisibility(operation, shouldApply, payload, actionKey) {
                const op = String(operation || '').toLowerCase();

                if (op === 'show_popup') {
                    const popupKey = actionKey && actionKey.length ? actionKey : 'form_popup';
                    const popupMessage = resolveActionMessagePayload(payload, {
                        currentFieldKey: '',
                        visited: []
                    }).replace(/\r\n/g, '\n');
                    const trimmedPopupMessage = popupMessage.trim();

                    if (!shouldApply) {
                        FORM_POPUP_STATE[popupKey] = false;
                        return;
                    }

                    if (!trimmedPopupMessage.length) {
                        FORM_POPUP_STATE[popupKey] = false;
                        return;
                    }

                    if (!FORM_POPUP_STATE[popupKey]) {
                        FORM_POPUP_STATE[popupKey] = true;
                        window.alert(popupMessage);
                    }

                    return;
                }

                const messageConfig = MESSAGE_OPERATION_MAP[op] || null;
                if (!messageConfig) {
                    return;
                }

                const resolvedKey = actionKey && actionKey.length
                    ? actionKey
                    : (messageConfig.type + '_form');

                const messageValue = resolveActionMessagePayload(payload, {
                    currentFieldKey: '',
                    visited: []
                });
                const normalizedMessage = messageValue.replace(/\r\n/g, '\n');
                const hasMessage = normalizedMessage.trim().length > 0;

                if (shouldApply && !hasMessage) {
                    toggleFormMessage(messageConfig, '', resolvedKey, false);
                    return;
                }

                toggleFormMessage(messageConfig, normalizedMessage, resolvedKey, shouldApply);
            }

            function refreshFormRedirectState() {
                const changeKeys = Object.keys(FORM_REDIRECT_STATE.changeTo);
                let redirectOverride = '';
                if (changeKeys.length) {
                    const lastKey = changeKeys[changeKeys.length - 1];
                    redirectOverride = (FORM_REDIRECT_STATE.changeTo[lastKey] || '').toString();
                }

                const appendSegments = [];
                Object.keys(FORM_REDIRECT_STATE.append).forEach(function(key) {
                    const segment = (FORM_REDIRECT_STATE.append[key] || '').toString();
                    if (segment.trim().length) {
                        appendSegments.push(segment);
                    }
                });

                if (typeof window.griffinformsFormRedirectOverrides !== 'object' || window.griffinformsFormRedirectOverrides === null) {
                    window.griffinformsFormRedirectOverrides = {};
                }
                if (typeof window.griffinformsFormRedirectAppends !== 'object' || window.griffinformsFormRedirectAppends === null) {
                    window.griffinformsFormRedirectAppends = {};
                }

                const trimmedOverride = redirectOverride.trim();
                if (trimmedOverride.length) {
                    window.griffinformsFormRedirectOverrides[formId] = { url: trimmedOverride };
                } else {
                    delete window.griffinformsFormRedirectOverrides[formId];
                }

                if (appendSegments.length) {
                    window.griffinformsFormRedirectAppends[formId] = { segments: appendSegments };
                } else {
                    delete window.griffinformsFormRedirectAppends[formId];
                }
            }

            function getVisibleFormPageContainer() {
                const container = $('.griffinforms-form' + formId + '-container');
                if (!container.length) {
                    return $();
                }
                const page = container.find('.griffinforms-formpage-container:visible').first();
                return page.length ? page : $();
            }

            function getSubmitButtonLabelElements() {
                // Target submit buttons (primary) across all pages, visible or hidden
                const container = $('.griffinforms-form' + formId + '-container');
                if (!container.length) {
                    return $();
                }
                return container.find('.griffinforms-formpage-container button.btn-primary .action-btn-label');
            }

            function getSubmitButtons() {
                const container = $('.griffinforms-form' + formId + '-container');
                if (!container.length) {
                    return $();
                }
                return container.find('.griffinforms-formpage-container button.btn-primary');
            }

            function ensureOriginalSubmitLabel(element) {
                if (!element || !element.length) {
                    return '';
                }
                let original = element.attr('data-gf-original-submit-label');
                if (typeof original !== 'string') {
                    original = element.data('gfOriginalSubmitLabel');
                }
                if (typeof original === 'string') {
                    element.data('gfOriginalSubmitLabel', original);
                    return original;
                }
                const TEXT_NODE = 3;
                const segments = [];
                element.contents().each(function() {
                    if (this.nodeType === TEXT_NODE) {
                        segments.push(this.nodeValue);
                    }
                });
                const fallback = segments.join('');
                element.attr('data-gf-original-submit-label', fallback);
                element.data('gfOriginalSubmitLabel', fallback);
                return fallback;
            }

            function setFormSubmitButtonLabel(payload) {
                const labelEls = getSubmitButtonLabelElements();
                if (!labelEls.length) {
                    return;
                }
                const resolverMeta = {};
                const normalized = normalizeExpected(payload, {
                    currentFieldKey: '',
                    visited: [],
                    purpose: 'action',
                    meta: resolverMeta
                });
                if (resolverMeta.abort) {
                    return;
                }
                let text;
                if (Array.isArray(normalized)) {
                    text = normalized.length ? normalized[0] : '';
                } else {
                    text = normalized;
                }
                if (text === null || typeof text === 'undefined') {
                    text = '';
                }
                const TEXT_NODE = 3;
                labelEls.each(function(){
                    const el = jQuery(this);
                    ensureOriginalSubmitLabel(el);
                    el.contents().filter(function(){ return this.nodeType === TEXT_NODE; }).remove();
                    el.prepend(document.createTextNode(String(text)));
                });
            }

            function captureOriginalSubmitDisabled() {
                if (FORM_SUBMIT_STATE.originalCaptured) {
                    return;
                }
                const buttons = getSubmitButtons();
                buttons.each(function(){
                    const btn = jQuery(this);
                    if (typeof btn.data('gfOriginalDisabled') === 'undefined') {
                        btn.data('gfOriginalDisabled', btn.is(':disabled'));
                    }
                });
                FORM_SUBMIT_STATE.originalCaptured = true;
            }

            function applyFormSubmitState(operation, shouldApply, actionKey) {
                captureOriginalSubmitDisabled();
                const op = String(operation || '').toLowerCase();
                const key = String(actionKey || op);
                if (shouldApply) {
                    if (op === 'disabled') {
                        FORM_SUBMIT_STATE.disable[key] = true;
                        delete FORM_SUBMIT_STATE.enable[key];
                    } else if (op === 'enabled') {
                        FORM_SUBMIT_STATE.enable[key] = true;
                        delete FORM_SUBMIT_STATE.disable[key];
                    }
                } else {
                    delete FORM_SUBMIT_STATE.disable[key];
                    delete FORM_SUBMIT_STATE.enable[key];
                }

                const buttons = getSubmitButtons();
                const hasEnable = Object.keys(FORM_SUBMIT_STATE.enable).length > 0;
                const hasDisable = Object.keys(FORM_SUBMIT_STATE.disable).length > 0;

                buttons.each(function(){
                    const btn = jQuery(this);
                    let shouldDisable;
                    if (hasEnable) {
                        shouldDisable = false;
                    } else if (hasDisable) {
                        shouldDisable = true;
                    } else {
                        shouldDisable = btn.data('gfOriginalDisabled') === true;
                    }
                    btn.prop('disabled', shouldDisable);
                    if (shouldDisable) {
                        btn.attr('disabled', 'disabled');
                    } else {
                        btn.removeAttr('disabled');
                    }
                    btn.attr('aria-disabled', shouldDisable ? 'true' : 'false');
                });
            }

            function setFieldValue(fieldId, payload) {
                const controls = getFieldControls(fieldId);
                if (!controls.length) {
                    return;
                }

                const fieldKey = String(fieldId);
                const resolverMeta = {};
                const normalizedPayload = normalizeExpected(payload, {
                    currentFieldKey: fieldKey,
                    visited: [fieldKey],
                    purpose: 'action',
                    meta: resolverMeta
                });
                if (resolverMeta.abort) {
                    return;
                }
                const valueList = (Array.isArray(normalizedPayload)
                    ? normalizedPayload
                    : [normalizedPayload])
                    .map(function(value) {
                        return String(value);
                    });

                const primaryValue = valueList.length ? valueList[0] : '';

                const checkboxSelector = '.griffinforms-formcontrol-' + fieldId + '-checkbox';
                const radioSelector = '.griffinforms-formcontrol-' + fieldId + '-radio';

                controls.each(function() {
                    const control = $(this);
                    const controlType = (control.attr('type') || '').toLowerCase();
                    const tagName = (control.prop('tagName') || '').toLowerCase();

                    if (control.is('[data-gf-file-meta]')) {
                        return;
                    }

                    if ('hidden' === controlType) {
                        const currentValue = control.val();
                        let newValue;
                        if (Array.isArray(normalizedPayload)) {
                            newValue = JSON.stringify(valueList);
                        } else {
                            newValue = primaryValue;
                        }

                        if (currentValue === newValue) {
                            return;
                        }

                        control.val(newValue);
                        control.trigger('change');
                        return;
                    }

                    if ('select' === tagName) {
                        if (Array.isArray(normalizedPayload)) {
                            const currentSelection = control.val() || [];
                            const normalizedCurrent = Array.isArray(currentSelection)
                                ? currentSelection.map(function(item) { return String(item); })
                                : [String(currentSelection)];

                            const sameLength = normalizedCurrent.length === valueList.length;
                            const sameValues = sameLength && normalizedCurrent.every(function(item) {
                                return valueList.includes(item);
                            });

                            if (sameValues) {
                                return;
                            }

                            control.val(valueList).trigger('change');
                            return;
                        }

                        const currentValue = control.val();
                        if (String(currentValue) === primaryValue) {
                            return;
                        }

                        control.val(primaryValue).trigger('change');
                        return;
                    }

                    if ('checkbox' === controlType || 'radio' === controlType) {
                        return;
                    }

                    const currentValue = control.val();
                    if (String(currentValue) === primaryValue) {
                        return;
                    }

                    control.val(primaryValue).trigger('input').trigger('change');
                });

                const checkboxes = $(checkboxSelector);
                if (checkboxes.length) {
                    checkboxes.each(function() {
                        const checkbox = $(this);
                        const shouldCheck = valueList.includes(String(checkbox.val()));
                        const isChecked = checkbox.is(':checked');
                        if (isChecked === shouldCheck) {
                            return;
                        }
                        checkbox.prop('checked', shouldCheck).trigger('change');
                    });
                }

                const radios = $(radioSelector);
                if (radios.length) {
                    const targetValue = primaryValue;
                    radios.each(function() {
                        const radio = $(this);
                        const matches = String(radio.val()) === targetValue;
                        const isChecked = radio.is(':checked');
                        if (isChecked === matches) {
                            return;
                        }
                        radio.prop('checked', matches).trigger('change');
                    });
                }
            }

            function applyFieldValue(fieldId, operation, payload, shouldApply) {
                if (!shouldApply) {
                    return;
                }

                const opKey = String(operation || '').toLowerCase();

                if (opKey === 'change_country_to' || opKey === 'change_city_to' || opKey === 'change_state_to') {
                    applyAddressComponentValue(fieldId, opKey, payload);
                    return;
                }

                if ('set' === opKey || 'change_to' === opKey) {
                    setFieldValue(fieldId, payload);
                }
            }

            function applyFormRedirection(operation, payload, shouldApply, actionKey) {
                const op = String(operation || '').toLowerCase();
                if (op !== 'change_to' && op !== 'append') {
                    return;
                }

                const resolvedValue = resolveActionMessagePayload(payload, {
                    currentFieldKey: '',
                    visited: []
                }).replace(/\r\n/g, '\n');

                const trimmedValue = resolvedValue.trim();

                if ('change_to' === op) {
                    if (shouldApply && trimmedValue.length) {
                        FORM_REDIRECT_STATE.changeTo[actionKey] = trimmedValue;
                    } else {
                        delete FORM_REDIRECT_STATE.changeTo[actionKey];
                    }
                }

                if ('append' === op) {
                    if (shouldApply && trimmedValue.length) {
                        FORM_REDIRECT_STATE.append[actionKey] = trimmedValue;
                    } else {
                        delete FORM_REDIRECT_STATE.append[actionKey];
                    }
                }

                refreshFormRedirectState();
            }

            function applyFieldState(fieldId, operation, shouldApply, actionKey) {
                const op = String(operation || '').toLowerCase();
                if (op !== 'disabled' && op !== 'enabled') {
                    return;
                }

                const entry = ensureFieldStateEntry(fieldId);
                const stateKey = String(actionKey || (op + '_' + fieldId));
                if (!stateKey.length) {
                    return;
                }

                if (op === 'disabled') {
                    if (shouldApply) {
                        entry.disable[stateKey] = true;
                    } else {
                        delete entry.disable[stateKey];
                    }
                } else if (op === 'enabled') {
                    if (shouldApply) {
                        entry.enable[stateKey] = true;
                    } else {
                        delete entry.enable[stateKey];
                    }
                }

                updateFieldDisabledState(fieldId);
            }

            function ensureOriginalLabel(labelElement) {
                if (!labelElement || !labelElement.length) {
                    return '';
                }

                let original = labelElement.attr('data-gf-original-label');
                if (typeof original !== 'string') {
                    original = labelElement.data('gfOriginalLabel');
                }

                if (typeof original === 'string') {
                    labelElement.data('gfOriginalLabel', original);
                    return original;
                }

                const TEXT_NODE = 3;
                const segments = [];

                labelElement.contents().each(function() {
                    if (this.nodeType === TEXT_NODE) {
                        segments.push(this.nodeValue);
                    }
                });

                const fallback = segments.join('');
                labelElement.attr('data-gf-original-label', fallback);
                labelElement.data('gfOriginalLabel', fallback);

                return fallback;
            }

            function setLabelElementText(labelElement, text) {
                if (!labelElement || !labelElement.length) {
                    return;
                }

                const TEXT_NODE = 3;
                labelElement.contents().filter(function() {
                    return this.nodeType === TEXT_NODE;
                }).remove();

                labelElement.prepend(document.createTextNode(String(text)));
            }

            function setFieldLabel(fieldId, payload) {
                const fieldKey = String(fieldId);
                const resolverMeta = {};
                const normalizedLabel = normalizeExpected(payload, {
                    currentFieldKey: fieldKey,
                    visited: [fieldKey],
                    purpose: 'action',
                    meta: resolverMeta
                });

                if (resolverMeta.abort) {
                    return;
                }

                let labelValue;
                if (Array.isArray(normalizedLabel)) {
                    labelValue = normalizedLabel.length ? normalizedLabel[0] : '';
                } else {
                    labelValue = normalizedLabel;
                }

                if (labelValue === null || typeof labelValue === 'undefined') {
                    labelValue = '';
                }

                const labelText = String(labelValue);
                const container = getFieldContainer(fieldId);
                if (!container.length) {
                    return;
                }

                const labelElement = container.find('label.form-label').first();
                if (!labelElement.length) {
                    return;
                }

                ensureOriginalLabel(labelElement);
                setLabelElementText(labelElement, labelText);
            }

            function applyFieldLabel(fieldId, operation, payload, shouldApply) {
                const op = String(operation || '').toLowerCase();

                if (ADDRESS_LABEL_OPERATIONS.has(op)) {
                    applyAddressLabelAction(fieldId, op, payload, shouldApply);
                    return;
                }

                const container = getFieldContainer(fieldId);
                if (!container.length) {
                    return;
                }

                const labelElement = container.find('label.form-label').first();
                if (!labelElement.length) {
                    return;
                }

                if (op === 'change_to') {
                    if (shouldApply) {
                        setFieldLabel(fieldId, payload);
                    }
                    else {
                        const originalText = ensureOriginalLabel(labelElement);
                        setLabelElementText(labelElement, originalText);
                    }
                    return;
                }

                if (op === 'add_class' || op === 'remove_class') {
                    const classes = normalizeClassList(payload);
                    if (!classes.length && op === 'add_class' && !shouldApply) {
                        return;
                    }

                    if (op === 'add_class') {
                        if (shouldApply) {
                            applyClassList(labelElement, classes, 'addClass');
                        } else if (classes.length) {
                            labelElement.removeClass(classes.join(' '));
                        }
                        return;
                    }

                    if (shouldApply) {
                        applyClassList(labelElement, classes, 'removeClass');
                    }
                }
            }

            function resolveActionValue(fieldId, payload) {
                const fieldKey = String(fieldId);
                const resolverMeta = {};
                const normalized = normalizeExpected(payload, {
                    currentFieldKey: fieldKey,
                    visited: [fieldKey],
                    purpose: 'action',
                    meta: resolverMeta
                });

                if (resolverMeta.abort) {
                    return '';
                }

                const extractString = function(value) {
                    if (value === null || typeof value === 'undefined') {
                        return '';
                    }
                    return String(value).trim();
                };

                if (Array.isArray(normalized)) {
                    for (let i = 0; i < normalized.length; i++) {
                        const candidate = extractString(normalized[i]);
                        if (candidate.length) {
                            return candidate;
                        }
                    }
                    return '';
                }

                return extractString(normalized);
            }

            function applyAddressLabelAction(fieldId, operation, payload, shouldApply) {
                const wrappers = $('.griffinforms-address-wrapper-' + fieldId);
                if (!wrappers.length) {
                    return;
                }

                const opKey = String(operation || '').toLowerCase();
                const keyMap = {
                    'change_line_1_label_to': 'line1',
                    'change_line_2_label_to': 'line2',
                    'change_city_label_to': 'city',
                    'change_state_label_to': 'state',
                    'change_country_label_to': 'country'
                };

                const labelKey = keyMap[opKey];
                if (!labelKey) {
                    return;
                }

                const resolvedValue = shouldApply ? resolveActionValue(fieldId, payload) : '';

                wrappers.each(function() {
                    const wrapper = $(this);
                    const labels = wrapper.find('label[data-gf-address-label="' + labelKey + '"]');
                    if (!labels.length) {
                        return;
                    }

                    labels.each(function() {
                        const label = $(this);
                        const originalText = ensureOriginalLabel(label);

                        if (shouldApply) {
                            setLabelElementText(label, resolvedValue.length ? resolvedValue : '');
                        } else {
                            setLabelElementText(label, originalText);
                        }
                    });
                });
            }

            function applyAddressComponentValue(fieldId, operation, payload) {
                const wrappers = $('.griffinforms-address-wrapper-' + fieldId);
                if (!wrappers.length) {
                    return;
                }

                const opKey = String(operation || '').toLowerCase();
                const rawValue = resolveActionValue(fieldId, payload);

                if (opKey === 'change_city_to') {
                    wrappers.each(function() {
                        const wrapper = $(this);
                        const cityInput = wrapper.find('.gf-address-city');
                        if (!cityInput.length) {
                            return;
                        }
                        const currentValue = String(cityInput.val() || '');
                        if (currentValue === rawValue) {
                            return;
                        }
                        cityInput.val(rawValue);
                        cityInput.trigger('input').trigger('change');
                    });
                    return;
                }

                if (opKey === 'change_country_to') {
                    const upperValue = rawValue.toUpperCase();
                    wrappers.each(function() {
                        const wrapper = $(this);
                        const countrySelect = wrapper.find('.gf-address-country');
                        if (!countrySelect.length) {
                            return;
                        }

                        const targetLower = rawValue.toLowerCase();
                        let targetValue = '';

                        if (upperValue.length && countrySelect.find('option[value="' + upperValue + '"]').length) {
                            targetValue = upperValue;
                        } else if (targetLower.length) {
                            countrySelect.find('option').each(function() {
                                const option = $(this);
                                if (option.text().trim().toLowerCase() === targetLower) {
                                    targetValue = option.val();
                                    return false;
                                }
                            });
                        }

                        if (!upperValue.length) {
                            targetValue = '';
                        }

                        const currentValue = String(countrySelect.val() || '');

                        if (targetValue === '') {
                            if (currentValue !== '') {
                                countrySelect.val('').trigger('change');
                            }
                            return;
                        }

                        if (currentValue !== targetValue) {
                            countrySelect.val(targetValue).trigger('change');
                        }
                    });
                    return;
                }

                if (opKey === 'change_state_to') {
                    const targetLower = rawValue.toLowerCase();
                    const targetUpper = rawValue.toUpperCase();

                    wrappers.each(function() {
                        const wrapper = $(this);
                        window.setTimeout(function() {
                            const selectWrap = wrapper.find('.gf-address-state-select-wrap');
                            const select = wrapper.find('.gf-address-state-select');
                            const inputWrap = wrapper.find('.gf-address-state-input-wrap');
                            const input = wrapper.find('.gf-address-state-input');

                            let matched = false;

                            if (select.length && !selectWrap.hasClass('d-none')) {
                                let valueToSet = '';
                                if (targetUpper.length && select.find('option[value="' + targetUpper + '"]').length) {
                                    valueToSet = targetUpper;
                                } else if (targetLower.length) {
                                    select.find('option').each(function() {
                                        const option = $(this);
                                        if (option.text().trim().toLowerCase() === targetLower) {
                                            valueToSet = option.val();
                                            return false;
                                        }
                                    });
                                }

                                if (!targetUpper.length && !targetLower.length) {
                                    valueToSet = '';
                                }

                                if (valueToSet !== '') {
                                    matched = true;
                                    const currentValue = String(select.val() || '');
                                    if (currentValue !== valueToSet) {
                                        select.val(valueToSet).trigger('change');
                                    }
                                } else if (!targetUpper.length && !targetLower.length) {
                                    matched = true;
                                    const currentValue = String(select.val() || '');
                                    if (currentValue !== '') {
                                        select.val('').trigger('change');
                                    }
                                }
                            }

                            if (!matched && input.length) {
                                if (selectWrap.length && !selectWrap.hasClass('d-none')) {
                                    selectWrap.addClass('d-none');
                                    select.addClass('d-none');
                                }

                                if (inputWrap.length) {
                                    inputWrap.removeClass('d-none');
                                }
                                input.removeClass('d-none');
                                const currentValue = String(input.val() || '');
                                if (currentValue !== rawValue) {
                                    input.val(rawValue);
                                    input.trigger('input').trigger('change');
                                }
                            }
                        }, 0);
                    });
                }
            }

            function ensureOriginalRowHeading(headingElement) {
                if (!headingElement || !headingElement.length) {
                    return '';
                }

                let original = headingElement.attr('data-gf-original-row-heading');
                if (typeof original !== 'string') {
                    original = headingElement.data('gfOriginalRowHeading');
                }

                if (typeof original === 'string') {
                    headingElement.data('gfOriginalRowHeading', original);
                    return original;
                }

                const TEXT_NODE = 3;
                const segments = [];
                headingElement.contents().each(function() {
                    if (this.nodeType === TEXT_NODE) {
                        segments.push(this.nodeValue);
                    }
                });

                const fallback = segments.join('');
                headingElement.attr('data-gf-original-row-heading', fallback);
                headingElement.data('gfOriginalRowHeading', fallback);

                return fallback;
            }

            function setRowHeading(rowId, payload) {
                const container = getRowContainer(rowId);
                if (!container.length) {
                    return;
                }

                const headingWrapper = container.find('.griffinforms-pagerow-heading .h6').first();
                if (!headingWrapper.length) {
                    return;
                }

                const resolverMeta = {};
                const normalizedHeading = normalizeExpected(payload, {
                    currentFieldKey: '',
                    visited: [],
                    purpose: 'action',
                    meta: resolverMeta
                });
                if (resolverMeta.abort) {
                    return;
                }

                let headingText;
                if (Array.isArray(normalizedHeading)) {
                    headingText = normalizedHeading.length ? normalizedHeading[0] : '';
                } else {
                    headingText = normalizedHeading;
                }

                if (headingText === null || typeof headingText === 'undefined') {
                    headingText = '';
                }

                ensureOriginalRowHeading(headingWrapper);

                const TEXT_NODE = 3;
                headingWrapper.contents().filter(function() {
                    return this.nodeType === TEXT_NODE;
                }).remove();

                headingWrapper.prepend(document.createTextNode(String(headingText)));
            }

            function applyRowHeadingClass(rowId, operation, payload, shouldApply) {
                const container = getRowContainer(rowId);
                if (!container.length) {
                    return;
                }

                const headingWrapper = container.find('.griffinforms-pagerow-heading .h6').first();
                if (!headingWrapper.length) {
                    return;
                }

                const op = String(operation || '').toLowerCase();
                const classes = normalizeClassList(payload);

                if (op === 'add_class') {
                    if (shouldApply) {
                        applyClassList(headingWrapper, classes, 'addClass');
                    } else if (classes.length) {
                        headingWrapper.removeClass(classes.join(' '));
                    }
                    return;
                }

                if (op === 'remove_class') {
                    if (shouldApply) {
                        applyClassList(headingWrapper, classes, 'removeClass');
                    }
                    return;
                }
            }

            function executeAction(action, shouldApply) {
                if (!action || typeof action !== 'object') {
                    return;
                }

                const actionItem = String(action.item || '').toLowerCase();
                const attribute = String(action.attribute || '').toLowerCase();
                const operation = String(action.action || '').toLowerCase();

                let actionKey = '';
                if (typeof action.__logicKey === 'string' && action.__logicKey.length) {
                    actionKey = action.__logicKey;
                } else if (typeof action.__id === 'string' && action.__id.length) {
                    actionKey = action.__id;
                    action.__logicKey = actionKey;
                } else {
                    actionKey = [
                        String(action.item_id || ''),
                        attribute,
                        operation
                    ].join('_');
                    action.__logicKey = actionKey;
                }

                if ('field' === actionItem) {
                    if ('visibility' === attribute) {
                        applyFieldVisibility(action.item_id, operation, shouldApply, action.input, actionKey);
                        return;
                    }

                    if ('state' === attribute) {
                        applyFieldState(action.item_id, operation, shouldApply, actionKey);
                        return;
                    }

                    if ('option_groups' === attribute) {
                        applySelectOptionGroups(action.item_id, operation, action.input, shouldApply, actionKey);
                        return;
                    }

                    if ('rows' === attribute) {
                        applyLikertRows(action.item_id, operation, action.input, shouldApply, actionKey);
                        return;
                    }

                    if ('value' === attribute) {
                        applyFieldValue(action.item_id, operation, action.input, shouldApply);
                        return;
                    }

                    if ('label' === attribute) {
                        applyFieldLabel(action.item_id, operation, action.input, shouldApply);
                    }
                    return;
                }

                if ('row' === actionItem) {
                    if ('visibility' === attribute) {
                        applyRowVisibility(action.item_id, operation, shouldApply, action.input);
                        return;
                    }
                    if ('heading' === attribute) {
                        if (operation === 'change_to') {
                            if (shouldApply) {
                                setRowHeading(action.item_id, action.input);
                            } else {
                                const container = getRowContainer(action.item_id);
                                const headingWrapper = container.find('.griffinforms-pagerow-heading .h6').first();
                                if (headingWrapper.length) {
                                    const originalText = ensureOriginalRowHeading(headingWrapper);
                                    const TEXT_NODE = 3;
                                    headingWrapper.contents().filter(function() {
                                        return this.nodeType === TEXT_NODE;
                                    }).remove();
                                    if (originalText.length) {
                                        headingWrapper.prepend(document.createTextNode(originalText));
                                    }
                                }
                            }
                            return;
                        }
                        if (operation === 'add_class' || operation === 'remove_class') {
                            applyRowHeadingClass(action.item_id, operation, action.input, shouldApply);
                            return;
                        }
                    }
                }

                if ('form' === actionItem) {
                    if ('visibility' === attribute) {
                        applyFormVisibility(operation, shouldApply, action.input, actionKey);
                        return;
                    }

                    if ('success_message' === attribute) {
                        applyFormSuccessMessage(operation, action.input, shouldApply, actionKey);
                        return;
                    }

                    if ('redirection' === attribute) {
                        applyFormRedirection(operation, action.input, shouldApply, actionKey);
                        return;
                    }

                    if ('submit_button_label' === attribute) {
                        if (operation === 'change_to') {
                            if (shouldApply) {
                                setFormSubmitButtonLabel(action.input);
                            } else {
                                const labelEls = getSubmitButtonLabelElements();
                                if (labelEls.length) {
                                    const TEXT_NODE = 3;
                                    labelEls.each(function(){
                                        const el = jQuery(this);
                                        const original = ensureOriginalSubmitLabel(el);
                                        el.contents().filter(function(){ return this.nodeType === TEXT_NODE; }).remove();
                                        if (original.length) {
                                            el.prepend(document.createTextNode(original));
                                        }
                                    });
                                }
                            }
                        }
                        return;
                    }

                    if ('submit_button_state' === attribute) {
                        applyFormSubmitState(operation, shouldApply, actionKey);
                        return;
                    }

                    return;
                }
            }
        <?php
    }

    // Emits per-rule execution wrappers that evaluate conditions and apply actions.
    protected function renderRuleExecutionJs($form_id, array $normalized_rules)
    {
        foreach ($normalized_rules as $rule_index => $rule) {
            ?>
            function runRule<?php echo (int) ($rule_index + 1); ?>() {
                const rule = formRulesConfig[<?php echo (int) $rule_index; ?>] || {};
                const allGroup = Array.isArray(rule.all) ? rule.all : [];
                const anyGroup = Array.isArray(rule.any) ? rule.any : [];

                const allMatch = allGroup.length === 0 ? true : rule<?php echo (int) ($rule_index + 1); ?>AllConditions();
                const anyMatch = anyGroup.length === 0 ? true : rule<?php echo (int) ($rule_index + 1); ?>AnyConditions();

                const ruleResult = allMatch && anyMatch;
                rule<?php echo (int) ($rule_index + 1); ?>Actions(ruleResult);
            }

            function rule<?php echo (int) ($rule_index + 1); ?>AllConditions() {
                <?php if (!empty($rule['all'])) : ?>
                    const results = [];
                    <?php foreach ($rule['all'] as $condition_index => $condition) : ?>
                        results.push(rule<?php echo (int) ($rule_index + 1); ?>AllCondition<?php echo (int) ($condition_index + 1); ?>());
                    <?php endforeach; ?>
                    return results.every(Boolean);
                <?php else : ?>
                    return true;
                <?php endif; ?>
            }

            <?php foreach ($rule['all'] as $condition_index => $condition) : ?>
            function rule<?php echo (int) ($rule_index + 1); ?>AllCondition<?php echo (int) ($condition_index + 1); ?>() {
                const condition = (formRulesConfig[<?php echo (int) $rule_index; ?>].all || [])[<?php echo (int) $condition_index; ?>];
                return evaluateCondition(condition);
            }
            <?php endforeach; ?>

            function rule<?php echo (int) ($rule_index + 1); ?>AnyConditions() {
                <?php if (!empty($rule['any'])) : ?>
                    const results = [];
                    <?php foreach ($rule['any'] as $condition_index => $condition) : ?>
                        results.push(rule<?php echo (int) ($rule_index + 1); ?>AnyCondition<?php echo (int) ($condition_index + 1); ?>());
                    <?php endforeach; ?>
                    return results.some(Boolean);
                <?php else : ?>
                    return true;
                <?php endif; ?>
            }

            <?php foreach ($rule['any'] as $condition_index => $condition) : ?>
            function rule<?php echo (int) ($rule_index + 1); ?>AnyCondition<?php echo (int) ($condition_index + 1); ?>() {
                const condition = (formRulesConfig[<?php echo (int) $rule_index; ?>].any || [])[<?php echo (int) $condition_index; ?>];
                return evaluateCondition(condition);
            }
            <?php endforeach; ?>

            function rule<?php echo (int) ($rule_index + 1); ?>Actions(ruleResult) {
                const actions = (formRulesConfig[<?php echo (int) $rule_index; ?>].actions || []);
                actions.forEach(function(action) {
                    executeAction(action, ruleResult);
                });
            }
            <?php
        }
        ?>

            function runForm<?php echo (int) $form_id; ?>Rules() {
                <?php foreach (array_keys($normalized_rules) as $rule_index) : ?>
                    runRule<?php echo (int) ($rule_index + 1); ?>();
                <?php endforeach; ?>
            }
        <?php
    }

    // Outputs trigger bindings that re-run rule evaluation when fields change.
    protected function renderRuleTriggersJs($form_id)
    {
        ?>
            runForm<?php echo (int) $form_id; ?>Rules();

            $(document).on('griffinforms:fieldChanged', function(event, context) {
                if (context && context.formId && parseInt(context.formId, 10) !== formId) {
                    return;
                }

                runForm<?php echo (int) $form_id; ?>Rules();
            });
        <?php
    }

    // Normalizes the raw conditional logic rules into a consistent structure.
    private function normalizeRules(array $rules)
    {
        $normalized = array();

        foreach ($rules as $rule) {
            if (!is_array($rule)) {
                continue;
            }

            $normalized_rule = array(
                'all' => array(),
                'any' => array(),
                'actions' => array(),
            );

            if (isset($rule['all']) && is_array($rule['all'])) {
                foreach ($rule['all'] as $condition) {
                    $normalized_condition = $this->normalizeCondition($condition);
                    if (null !== $normalized_condition) {
                        $normalized_rule['all'][] = $normalized_condition;
                    }
                }
            }

            if (isset($rule['any']) && is_array($rule['any'])) {
                foreach ($rule['any'] as $condition) {
                    $normalized_condition = $this->normalizeCondition($condition);
                    if (null !== $normalized_condition) {
                        $normalized_rule['any'][] = $normalized_condition;
                    }
                }
            }

            if (isset($rule['actions']) && is_array($rule['actions'])) {
                foreach ($rule['actions'] as $action) {
                    $normalized_action = $this->normalizeAction($action);
                    if (null !== $normalized_action) {
                        $normalized_rule['actions'][] = $normalized_action;
                    }
                }
            }

            if (empty($normalized_rule['all']) && empty($normalized_rule['any']) && empty($normalized_rule['actions'])) {
                continue;
            }

            $normalized['rule_' . (count($normalized) + 1)] = $normalized_rule;
        }

        return array_values($normalized);
    }

    // Normalizes a single condition definition pulled from storage.
    private function normalizeCondition($condition)
    {
        if (!is_array($condition)) {
            return null;
        }

        $item = isset($condition['item']) ? (string) $condition['item'] : '';
        $item_id = isset($condition['item_id']) ? (string) $condition['item_id'] : '';
        $attribute = isset($condition['attribute']) ? (string) $condition['attribute'] : '';
        $evaluator = isset($condition['evaluator']) ? (string) $condition['evaluator'] : '';
        $input = isset($condition['input']) ? $condition['input'] : '';

        if ('' === $item || '' === $item_id || '' === $attribute) {
            return null;
        }

        return array(
            'item' => $item,
            'item_id' => $item_id,
            'attribute' => $attribute,
            'evaluator' => $evaluator,
            'input' => $input,
        );
    }

    // Normalizes a single action definition pulled from storage.
    private function normalizeAction($action)
    {
        if (!is_array($action)) {
            return null;
        }

        $item = isset($action['item']) ? (string) $action['item'] : '';
        $item_id = isset($action['item_id']) ? (string) $action['item_id'] : '';
        $attribute = isset($action['attribute']) ? (string) $action['attribute'] : '';
        $operation = isset($action['action']) ? (string) $action['action'] : '';
        $input = isset($action['input']) ? $action['input'] : '';

        if ('' === $item || '' === $item_id || '' === $attribute) {
            return null;
        }

        static $action_counter = 0;
        $action_counter++;

        return array(
            'item' => $item,
            'item_id' => $item_id,
            'attribute' => $attribute,
            'action' => $operation,
            'input' => $input,
            '__id' => 'action_' . $action_counter,
        );
    }
}
