    (function ($) {
    'use strict';

    function toggleGroup(section) {
        var $section = $(section);
        var $body = $section.find('.wooproduct-exporter__group-body');

        $section.toggleClass('is-collapsed');
        $body.stop(true, true).slideToggle(180);
    }

    function toggleAllCheckboxes(selectAll) {
        var $checkboxes = $('.wooproduct-exporter__field-control input[type="checkbox"]');

        $checkboxes.prop('checked', selectAll).trigger('change');
    }

    function ConditionBuilder($root, config) {
        this.$root = $root;
        this.$input = $root.find('[data-condition-builder-input]');
        this.$body = $root.find('[data-condition-builder-body]');
        this.config = config || {};
        this.fields = config.fields || {};
        this.text = config.text || {};
        this.operatorLabels = config.operatorLabels || {};
        this.state = this.parseState(config.initial || {});
        this.bindEvents();
        this.render();
    }

    ConditionBuilder.prototype.getFieldKeys = function () {
        return Object.keys(this.fields);
    };

    ConditionBuilder.prototype.parseState = function (raw) {
        var fallback = { relation: 'AND', groups: [] };

        if (!raw || typeof raw !== 'object') {
            return fallback;
        }

        var relation = String(raw.relation || 'AND').toUpperCase();
        if (relation !== 'OR') {
            relation = 'AND';
        }

        var groups = Array.isArray(raw.groups) ? raw.groups : [];

        groups = groups.map(function (group) {
            var groupRelation = String((group && group.relation) || 'AND').toUpperCase();
            if (groupRelation !== 'OR') {
                groupRelation = 'AND';
            }

            var conditions = Array.isArray(group && group.conditions) ? group.conditions : [];

            conditions = conditions.map(function (condition) {
                var fieldKeys = Object.keys(this.fields);
                var field = condition && condition.field;

                if (!field || fieldKeys.indexOf(field) === -1) {
                    field = fieldKeys[0] || '';
                }

                var definition = this.fields[field] || {};
                var operators = definition.operators || [];
                var operator = condition && condition.operator;

                if (!operator || operators.indexOf(operator) === -1) {
                    operator = operators[0] || 'eq';
                }

                return {
                    field: field,
                    operator: operator,
                    value: condition ? condition.value : '',
                    value_to: condition ? condition.value_to : '',
                };
            }.bind(this));

            return {
                relation: groupRelation,
                conditions: conditions,
            };
        }.bind(this));

        return {
            relation: relation,
            groups: groups,
        };
    };

    ConditionBuilder.prototype.bindEvents = function () {
        var self = this;

        this.$body.on('click', '[data-action="add-group"]', function (event) {
            event.preventDefault();
            self.addGroup();
        });

        this.$body.on('click', '[data-action="remove-group"]', function (event) {
            event.preventDefault();
            var index = parseInt($(this).closest('[data-group-index]').data('group-index'), 10);
            self.removeGroup(index);
        });

        this.$body.on('click', '[data-action="add-condition"]', function (event) {
            event.preventDefault();
            var groupIndex = parseInt($(this).closest('[data-group-index]').data('group-index'), 10);
            self.addCondition(groupIndex);
        });

        this.$body.on('click', '[data-action="remove-condition"]', function (event) {
            event.preventDefault();
            var $condition = $(this).closest('[data-condition-index]');
            var groupIndex = parseInt($condition.closest('[data-group-index]').data('group-index'), 10);
            var conditionIndex = parseInt($condition.data('condition-index'), 10);
            self.removeCondition(groupIndex, conditionIndex);
        });

        this.$body.on('change', '[data-relation-control]', function () {
            var value = $(this).val();
            self.updateRelation(value);
        });

        this.$body.on('change', '[data-group-relation]', function () {
            var value = $(this).val();
            var groupIndex = parseInt($(this).closest('[data-group-index]').data('group-index'), 10);
            self.updateGroupRelation(groupIndex, value);
        });

        this.$body.on('change', '[data-field-select]', function () {
            var $row = $(this).closest('[data-condition-index]');
            var groupIndex = parseInt($row.closest('[data-group-index]').data('group-index'), 10);
            var conditionIndex = parseInt($row.data('condition-index'), 10);
            var field = $(this).val();
            self.updateConditionField(groupIndex, conditionIndex, field);
        });

        this.$body.on('change', '[data-operator-select]', function () {
            var $row = $(this).closest('[data-condition-index]');
            var groupIndex = parseInt($row.closest('[data-group-index]').data('group-index'), 10);
            var conditionIndex = parseInt($row.data('condition-index'), 10);
            var operator = $(this).val();
            self.updateConditionOperator(groupIndex, conditionIndex, operator);
        });

        this.$body.on('input', '[data-value-input]', function () {
            var $row = $(this).closest('[data-condition-index]');
            var groupIndex = parseInt($row.closest('[data-group-index]').data('group-index'), 10);
            var conditionIndex = parseInt($row.data('condition-index'), 10);
            var fieldName = $(this).data('value-input');
            self.updateConditionValue(groupIndex, conditionIndex, fieldName, $(this).val());
        });
    };

    ConditionBuilder.prototype.ensureStatePersistence = function () {
        this.$input.val(JSON.stringify(this.state));
    };

    ConditionBuilder.prototype.addGroup = function () {
        var fieldKeys = this.getFieldKeys();

        if (!fieldKeys.length) {
            return;
        }

        var fieldKey = fieldKeys[0];
        var operators = this.fields[fieldKey].operators || [];
        var operator = operators[0] || 'eq';

        this.state.groups.push({
            relation: 'AND',
            conditions: [
                {
                    field: fieldKey,
                    operator: operator,
                    value: '',
                    value_to: '',
                },
            ],
        });

        this.render();
    };

    ConditionBuilder.prototype.removeGroup = function (groupIndex) {
        if (groupIndex < 0 || groupIndex >= this.state.groups.length) {
            return;
        }

        this.state.groups.splice(groupIndex, 1);
        this.render();
    };

    ConditionBuilder.prototype.addCondition = function (groupIndex) {
        var group = this.state.groups[groupIndex];

        if (!group) {
            return;
        }

        var fieldKeys = this.getFieldKeys();

        if (!fieldKeys.length) {
            return;
        }

        var fieldKey = fieldKeys[0];
        var operators = this.fields[fieldKey].operators || [];
        var operator = operators[0] || 'eq';

        group.conditions.push({
            field: fieldKey,
            operator: operator,
            value: '',
            value_to: '',
        });

        this.render();
    };

    ConditionBuilder.prototype.removeCondition = function (groupIndex, conditionIndex) {
        var group = this.state.groups[groupIndex];

        if (!group || conditionIndex < 0 || conditionIndex >= group.conditions.length) {
            return;
        }

        group.conditions.splice(conditionIndex, 1);

        if (!group.conditions.length) {
            this.state.groups.splice(groupIndex, 1);
        }

        this.render();
    };

    ConditionBuilder.prototype.updateRelation = function (value) {
        this.state.relation = value === 'OR' ? 'OR' : 'AND';
        this.ensureStatePersistence();
    };

    ConditionBuilder.prototype.updateGroupRelation = function (groupIndex, value) {
        var group = this.state.groups[groupIndex];

        if (!group) {
            return;
        }

        group.relation = value === 'OR' ? 'OR' : 'AND';
        this.ensureStatePersistence();
    };

    ConditionBuilder.prototype.updateConditionField = function (groupIndex, conditionIndex, field) {
        var group = this.state.groups[groupIndex];
        var condition = group && group.conditions[conditionIndex];

        if (!condition || !this.fields[field]) {
            return;
        }

        var operators = this.fields[field].operators || [];
        condition.field = field;

        if (operators.indexOf(condition.operator) === -1) {
            condition.operator = operators[0] || 'eq';
        }

        condition.value = '';
        condition.value_to = '';

        this.render();
    };

    ConditionBuilder.prototype.updateConditionOperator = function (groupIndex, conditionIndex, operator) {
        var group = this.state.groups[groupIndex];
        var condition = group && group.conditions[conditionIndex];

        if (!condition) {
            return;
        }

        condition.operator = operator;

        if (operator !== 'between') {
            condition.value_to = '';
        }

        this.ensureStatePersistence();
        this.render();
    };

    ConditionBuilder.prototype.updateConditionValue = function (groupIndex, conditionIndex, fieldName, value) {
        var group = this.state.groups[groupIndex];
        var condition = group && group.conditions[conditionIndex];

        if (!condition) {
            return;
        }

        condition[fieldName] = value;
        this.ensureStatePersistence();
    };

    ConditionBuilder.prototype.render = function () {
        var self = this;

        if (!this.getFieldKeys().length) {
            this.$body.html('<p class="wc-pce-condition-builder__empty">' + (this.text.emptyState || '') + '</p>');
            this.ensureStatePersistence();
            return;
        }

        var html = '';

        html += '<div class="wc-pce-condition-builder__top">';
        html += '<label>';
        html += '<span>' + (this.text.relationLabel || '') + '</span>';
        html += '<select data-relation-control>';
        html += '<option value="AND"' + (this.state.relation === 'AND' ? ' selected' : '') + '>AND</option>';
        html += '<option value="OR"' + (this.state.relation === 'OR' ? ' selected' : '') + '>OR</option>';
        html += '</select>';
        html += '</label>';
        html += '<button class="button button-secondary" data-action="add-group">' + (this.text.addGroup || 'Add group') + '</button>';
        html += '</div>';

        if (!this.state.groups.length) {
            html += '<div class="wc-pce-condition-builder__empty">' + (this.text.emptyState || '') + '</div>';
        }

        html += '<div class="wc-pce-condition-builder__groups">';

        this.state.groups.forEach(function (group, groupIndex) {
            html += '<div class="wc-pce-condition-builder__group" data-group-index="' + groupIndex + '">';
            html += '<div class="wc-pce-condition-builder__group-header">';
            html += '<div class="wc-pce-condition-builder__group-relation">';
            html += '<span>' + (self.text.groupRelation || '') + '</span>';
            html += '<select data-group-relation>';
            html += '<option value="AND"' + (group.relation === 'AND' ? ' selected' : '') + '>AND</option>';
            html += '<option value="OR"' + (group.relation === 'OR' ? ' selected' : '') + '>OR</option>';
            html += '</select>';
            html += '</div>';
            html += '<button class="button button-link-delete" data-action="remove-group">' + (self.text.removeGroup || 'Remove group') + '</button>';
            html += '</div>';

            html += '<div class="wc-pce-condition-builder__conditions">';

            group.conditions.forEach(function (condition, conditionIndex) {
                html += '<div class="wc-pce-condition-builder__condition" data-condition-index="' + conditionIndex + '">';

                html += '<label>';
                html += '<span>' + (self.text.fieldLabel || 'Field') + '</span>';
                html += '<select data-field-select>';
                self.getFieldKeys().forEach(function (fieldKey) {
                    var label = self.fields[fieldKey].label || fieldKey;
                    html += '<option value="' + fieldKey + '"' + (condition.field === fieldKey ? ' selected' : '') + '>' + label + '</option>';
                });
                html += '</select>';
                html += '</label>';

                html += '<label>';
                html += '<span>' + (self.text.operatorLabel || 'Operator') + '</span>';
                html += '<select data-operator-select>';
                (self.fields[condition.field].operators || []).forEach(function (operatorKey) {
                    var operatorLabel = self.operatorLabels[operatorKey] || operatorKey;
                    html += '<option value="' + operatorKey + '"' + (condition.operator === operatorKey ? ' selected' : '') + '>' + operatorLabel + '</option>';
                });
                html += '</select>';
                html += '</label>';

                html += '<label>';
                html += '<span>' + (self.text.valueLabel || 'Value') + '</span>';
                html += '<input type="number" step="any" data-value-input="value" value="' + (condition.value || '') + '" />';
                html += '</label>';

                if (condition.operator === 'between') {
                    html += '<label>';
                    html += '<span>' + (self.text.valueToLabel || 'and') + '</span>';
                    html += '<input type="number" step="any" data-value-input="value_to" value="' + (condition.value_to || '') + '" />';
                    html += '</label>';
                }

                html += '<button class="button button-link-delete" data-action="remove-condition">' + (self.text.removeCondition || 'Remove') + '</button>';
                html += '</div>';
            });

            html += '<button class="button button-secondary" data-action="add-condition">' + (self.text.addCondition || 'Add condition') + '</button>';
            html += '</div>'; // conditions
            html += '</div>'; // group
        });

        html += '</div>'; // groups wrapper

        this.$body.html(html);
        this.ensureStatePersistence();
    };

    ConditionBuilder.prototype.setState = function (raw) {
        this.state = this.parseState(raw || {});
        this.render();
    };

    function FieldOrdering(options) {
        options = options || {};
        this.$form = options.form || $();
        this.$panel = options.panel || $();
        this.$list = options.list || $();
        this.$input = options.input || $();
        this.$hint = options.hint || $();
        this.$empty = options.empty || $();
        this.definitions = options.definitions || {};
        this.privateLabel = options.privateLabel || '';
        this.strings = options.strings || {};
        this.initial = Array.isArray(options.initial) ? options.initial : [];
        this.$checkboxes = this.$form.length ? this.$form.find('input[name="fields[]"]') : $();
        this.suspendSync = false;
        this.selected = [];
        this.isReady = this.$panel.length && this.$list.length && this.$checkboxes.length;

        if (!this.isReady) {
            return;
        }

        this.bind();
    }

    FieldOrdering.prototype.bind = function () {
        var self = this;

        this.selected = this.normalize(this.initial);

        this.$list.sortable({
            axis: 'y',
            items: '[data-field-key]',
            handle: '[data-field-drag]',
            placeholder: 'wc-pce-selected-fields__placeholder',
            update: function () {
                self.syncOrderFromDom();
            },
        });

        this.$checkboxes.on('change', function () {
            if (self.suspendSync) {
                return;
            }

            self.rebuildFromChecked();
        });

        this.$list.on('click', '[data-field-remove]', function (event) {
            event.preventDefault();
            var key = $(this).closest('[data-field-key]').data('field-key');

            if (!key) {
                return;
            }

            self.setCheckbox(key, false);
            self.rebuildFromChecked();
        });

        this.rebuildFromChecked();
    };

    FieldOrdering.prototype.normalize = function (order) {
        var seen = {};
        var valid = this.collectValidKeys();
        var normalized = [];

        (order || []).forEach(function (key) {
            if (!key || seen[key] || valid.indexOf(key) === -1) {
                return;
            }

            seen[key] = true;
            normalized.push(key);
        });

        return normalized;
    };

    FieldOrdering.prototype.collectValidKeys = function () {
        var keys = [];

        this.$checkboxes.each(function () {
            var value = $(this).val();

            if (value && keys.indexOf(value) === -1) {
                keys.push(value);
            }
        });

        return keys;
    };

    FieldOrdering.prototype.collectCheckedKeys = function () {
        var keys = [];

        this.$checkboxes.filter(':checked').each(function () {
            var value = $(this).val();

            if (value) {
                keys.push(value);
            }
        });

        return keys;
    };

    FieldOrdering.prototype.rebuildFromChecked = function () {
        var checked = this.collectCheckedKeys();
        var preserved = this.selected.filter(function (key) {
            return checked.indexOf(key) !== -1;
        });

        checked.forEach(function (key) {
            if (preserved.indexOf(key) === -1) {
                preserved.push(key);
            }
        });

        this.selected = this.normalize(preserved);
        this.render();
    };

    FieldOrdering.prototype.render = function () {
        var self = this;
        var selection = this.selected.slice();

        this.$list.empty();

        if (!selection.length) {
            if (this.$empty.length) {
                this.$empty.removeAttr('hidden');
                this.$list.append(this.$empty);
            }

            this.updateHint();
            this.syncInput();
            return;
        }

        if (this.$empty.length) {
            this.$empty.attr('hidden', true);
        }

        selection.forEach(function (key, index) {
            var definition = self.definitions[key] || {};
            var label = definition.label || key;
            var isPrivate = !!definition.is_private;
            var $item = $('<li>', { 'class': 'wc-pce-selected-fields__item' }).attr('data-field-key', key);

            $('<span>', { 'class': 'wc-pce-selected-fields__drag', 'data-field-drag': '', 'aria-hidden': 'true' }).text('⋮⋮').appendTo($item);
            $('<span>', { 'class': 'wc-pce-selected-fields__index' }).text(index + 1).appendTo($item);

            var $label = $('<div>', { 'class': 'wc-pce-selected-fields__label' });
            $('<span>', { 'class': 'wc-pce-selected-fields__label-text' }).text(label).appendTo($label);

            if (isPrivate && self.privateLabel) {
                $('<span>', { 'class': 'wc-pce-selected-fields__badge' }).text(self.privateLabel).appendTo($label);
            }

            $label.appendTo($item);

            var removeText = self.strings.remove || 'Remove';
            var removeLabel = self.strings.removeColumn ? self.strings.removeColumn.replace('%s', label) : removeText;

            $('<button>', {
                type: 'button',
                'class': 'button-link wc-pce-selected-fields__remove',
                'data-field-remove': '',
                'aria-label': removeLabel,
            }).text(removeText).appendTo($item);

            self.$list.append($item);
        });

        this.updateIndexes();
        this.updateHint();
        this.syncInput();
    };

    FieldOrdering.prototype.updateIndexes = function () {
        this.$list.children('[data-field-key]').each(function (index) {
            $(this).find('.wc-pce-selected-fields__index').text(index + 1);
        });
    };

    FieldOrdering.prototype.updateHint = function () {
        if (!this.$hint.length) {
            return;
        }

        if (this.selected.length > 1 && this.strings.dragHint) {
            this.$hint.text(this.strings.dragHint).removeAttr('hidden');
        } else {
            this.$hint.attr('hidden', true);
        }
    };

    FieldOrdering.prototype.syncInput = function () {
        if (!this.$input.length) {
            return;
        }

        this.$input.val(this.selected.length ? JSON.stringify(this.selected) : '');
    };

    FieldOrdering.prototype.syncOrderFromDom = function () {
        var order = [];

        this.$list.children('[data-field-key]').each(function () {
            var key = $(this).data('field-key');

            if (key) {
                order.push(String(key));
            }
        });

        this.selected = this.normalize(order);
        this.updateIndexes();
        this.updateHint();
        this.syncInput();
    };

    FieldOrdering.prototype.setCheckbox = function (key, state) {
        this.suspendSync = true;
        this.$checkboxes.filter('[value="' + key + '"]').prop('checked', !!state);
        this.suspendSync = false;
    };

    FieldOrdering.prototype.applySelection = function (order) {
        this.selected = this.normalize(order);
        this.suspendSync = true;

        this.$checkboxes.prop('checked', false);
        this.selected.forEach(function (key) {
            this.$checkboxes.filter('[value="' + key + '"]').prop('checked', true);
        }, this);

        this.suspendSync = false;
        this.render();
    };

    FieldOrdering.prototype.getSelection = function () {
        return this.selected.slice();
    };

    function PreviewModal(options) {
        options = options || {};
        this.$form = options.form || $();
        this.ajax = options.ajax || {};
        this.config = options.config || {};
        this.$modal = options.modal || $();
        this.$triggers = options.triggers || $();
        this.$loading = this.$modal.find('[data-preview-loading]');
        this.$error = this.$modal.find('[data-preview-error]');
        this.$summary = this.$modal.find('[data-preview-summary]');
        this.$tableWrapper = this.$modal.find('[data-preview-table-wrapper]');
        this.$table = this.$modal.find('[data-preview-table]');
        this.$tableHead = this.$table.find('thead');
        this.$tableBody = this.$table.find('tbody');
        this.$document = $(document);
        this.isOpen = false;
        this.activeRequest = null;
        this.strings = this.config.strings || {};
        this.limit = parseInt(this.config.limit, 10);
        this.columnMinWidth = parseInt(this.config.columnMinWidth, 10);
        this.metaColumnMinWidth = parseInt(this.config.metaColumnMinWidth, 10);

        if (isNaN(this.limit) || this.limit <= 0) {
            this.limit = 20;
        }

        if (isNaN(this.columnMinWidth) || this.columnMinWidth <= 0) {
            this.columnMinWidth = 120;
        }

        if (isNaN(this.metaColumnMinWidth) || this.metaColumnMinWidth <= 0) {
            this.metaColumnMinWidth = 240;
        }

        this.handleKeydown = this.handleKeydown.bind(this);

        this.bindEvents();
    }

    PreviewModal.prototype.bindEvents = function () {
        var self = this;

        if (!this.$modal.length) {
            return;
        }

        this.$triggers.on('click', function (event) {
            event.preventDefault();
            self.openAndFetch();
        });

        this.$modal.on('click', function (event) {
            if (event.target === self.$modal.get(0)) {
                self.close();
            }
        });

        this.$modal.find('[data-preview-close]').on('click', function (event) {
            event.preventDefault();
            self.close();
        });
    };

    PreviewModal.prototype.openAndFetch = function () {
        this.open();
        this.resetState();

        if (!this.$form.length) {
            this.showError(this.getString('error') || 'Unable to load preview.');
            return;
        }

        if (!this.$form.find('input[name="fields[]"]:checked').length) {
            this.hideLoading();
            this.showError(this.getString('noFields') || 'Select at least one column to preview.');
            return;
        }

        this.fetchPreview();
    };

    PreviewModal.prototype.open = function () {
        if (!this.$modal.length || this.isOpen) {
            return;
        }

        this.$modal.removeAttr('hidden');
        $('body').addClass('wc-pce-modal-open');
        this.$document.on('keydown', this.handleKeydown);
        this.isOpen = true;
    };

    PreviewModal.prototype.close = function () {
        if (!this.isOpen) {
            return;
        }

        this.abortRequest();
        this.$modal.attr('hidden', true);
        $('body').removeClass('wc-pce-modal-open');
        this.$document.off('keydown', this.handleKeydown);
        this.isOpen = false;
    };

    PreviewModal.prototype.handleKeydown = function (event) {
        if ('Escape' === event.key || 27 === event.keyCode) {
            this.close();
        }
    };

    PreviewModal.prototype.resetState = function () {
        this.hideError();
        this.hideSummary();
        this.hideTable();
        this.showLoading();
    };

    PreviewModal.prototype.showLoading = function () {
        if (this.$loading.length) {
            this.$loading.prop('hidden', false).css('display', 'grid');
        }
    };

    PreviewModal.prototype.hideLoading = function () {
        if (this.$loading.length) {
            this.$loading.prop('hidden', true).css('display', 'none');
        }
    };

    PreviewModal.prototype.showError = function (message) {
        this.hideSummary();
        this.hideTable();
        this.hideLoading();

        if (this.$error.length) {
            this.$error.text(message || this.getString('error') || 'Unable to load preview.').removeAttr('hidden');
        }
    };

    PreviewModal.prototype.hideError = function () {
        if (this.$error.length) {
            this.$error.attr('hidden', true).text('');
        }
    };

    PreviewModal.prototype.showSummary = function (message) {
        if (this.$summary.length) {
            this.$summary.text(message).removeAttr('hidden');
        }
    };

    PreviewModal.prototype.hideSummary = function () {
        if (this.$summary.length) {
            this.$summary.attr('hidden', true).text('');
        }
    };

    PreviewModal.prototype.showTable = function () {
        if (this.$tableWrapper.length) {
            this.$tableWrapper.removeAttr('hidden');
        }
    };

    PreviewModal.prototype.hideTable = function () {
        if (this.$tableWrapper.length) {
            this.$tableWrapper.attr('hidden', true);
        }

        if (this.$tableHead.length) {
            this.$tableHead.empty();
        }

        if (this.$tableBody.length) {
            this.$tableBody.empty();
        }
    };

    PreviewModal.prototype.abortRequest = function () {
        if (this.activeRequest && typeof this.activeRequest.abort === 'function') {
            this.activeRequest.abort();
        }

        this.activeRequest = null;
    };

    PreviewModal.prototype.fetchPreview = function () {
        var action = this.ajax.actions ? this.ajax.actions.preview : '';

        if (!this.ajax.url || !action) {
            this.showError(this.getString('error') || 'Unable to load preview.');
            return;
        }

        var payload = this.serializeForm();
        payload.action = action;
        payload.nonce = this.config.nonce || '';
        payload.limit = this.limit;

        var self = this;

        this.abortRequest();

        this.activeRequest = $.ajax({
            url: this.ajax.url,
            method: 'POST',
            data: payload,
            dataType: 'json'
        })
            .done(function (response) {
                self.activeRequest = null;

                if (!response || !response.success || !response.data) {
                    self.showError(self.getString('error') || 'Unable to load preview.');
                    return;
                }

                self.renderResponse(response.data);
            })
            .fail(function (jqXHR) {
                self.activeRequest = null;
                self.showError(self.extractErrorMessage(jqXHR));
            });
    };

    PreviewModal.prototype.extractErrorMessage = function (jqXHR) {
        if (jqXHR && jqXHR.responseJSON && jqXHR.responseJSON.data && jqXHR.responseJSON.data.message) {
            return jqXHR.responseJSON.data.message;
        }

        return this.getString('error') || 'Unable to load preview. Please try again.';
    };

    PreviewModal.prototype.renderResponse = function (data) {
        this.hideLoading();
        this.hideError();

        var columns = Array.isArray(data.columns) ? data.columns : [];
        var rows = Array.isArray(data.rows) ? data.rows : [];
        var count = typeof data.count === 'number' ? data.count : rows.length;
        var truncated = !!data.truncated;
        var limit = typeof data.limit === 'number' ? data.limit : this.limit;

        if (!columns.length && rows.length) {
            columns = this.buildColumnsFromRow(rows[0]);
        }

        if (!columns.length) {
            this.hideTable();
            this.showSummary(this.getString('empty') || 'No data found for the selected filters.');
            return;
        }

        this.renderTable(columns, rows);

        if (!rows.length) {
            this.showSummary(this.getString('empty') || 'No data found for the selected filters.');
            return;
        }

        var summary = truncated
            ? this.formatString(this.getString('summaryLimit') || 'Showing first %1$s rows.', limit)
            : this.formatString(this.getString('summaryExact') || 'Showing %1$s rows.', count);

        this.showSummary(summary);
    };

    PreviewModal.prototype.renderTable = function (columns, rows) {
        var self = this;
        var keys = columns.map(function (column) {
            return column.key;
        });
        var metaFlags = columns.map(function (column) {
            return 'meta' === (column.group || '');
        });

        this.$tableHead.empty();
        this.$tableBody.empty();

        var $headerRow = $('<tr/>');

        columns.forEach(function (column, index) {
            var isMeta = metaFlags[index];
            var $th = $('<th/>', {
                'data-column-index': index,
                'data-column-key': column.key || ''
            }).text(column.label || column.key || '');

            if (column.private) {
                $th.addClass('is-private');
            }

            if (isMeta) {
                $th.addClass('is-meta');
            }

            $headerRow.append($th);
        });

        this.$tableHead.append($headerRow);

        var columnWidths = this.calculateColumnWidths(metaFlags);
        this.applyHeaderWidths(columnWidths);
        columnWidths = this.calculateColumnWidths(metaFlags);
        this.columnWidths = columnWidths;

        rows.forEach(function (row) {
            var $row = $('<tr/>');

            keys.forEach(function (key, index) {
                var value;
                var isMeta = metaFlags[index];
                var columnWidth = columnWidths[index];

                if (row && Object.prototype.hasOwnProperty.call(row, key)) {
                    value = row[key];
                } else {
                    value = '';
                }

                if (Array.isArray(value)) {
                    value = value.join(', ');
                } else if (value === null || typeof value === 'undefined') {
                    value = '';
                } else if (typeof value === 'object') {
                    try {
                        value = JSON.stringify(value);
                    } catch (error) {
                        value = '' + value;
                    }
                }

                value = value === null || typeof value === 'undefined' ? '' : String(value);

                var $cell = $('<td/>', {
                    'data-column-index': index
                });

                self.setElementWidth($cell, columnWidth);

                if (columns[index] && columns[index].private) {
                    $cell.addClass('is-private');
                }

                if (isMeta) {
                    $cell.addClass('is-meta');
                }

                var $content = $('<div/>', {
                    class: 'wc-pce-preview__cell-text',
                    text: value
                });

                if (value) {
                    $content.attr('title', value);
                }

                $cell.append($content);
                $row.append($cell);
            });

            self.$tableBody.append($row);
        });

        this.updateTableWidth(columnWidths);
        this.showTable();
    };

    PreviewModal.prototype.calculateColumnWidths = function (metaFlags) {
        var widths = [];

        var self = this;

        this.$tableHead.find('th').each(function (index, th) {
            var $th = $(th);
            var measured = Math.ceil($th.outerWidth());

            if (!measured || measured <= 0 || !isFinite(measured)) {
                measured = self.columnMinWidth;
            }

            measured = Math.max(measured, self.columnMinWidth);

            if (Array.isArray(metaFlags) && metaFlags[index]) {
                measured = Math.max(measured, self.metaColumnMinWidth);
            }

            widths[index] = measured;
        });

        return widths;
    };

    PreviewModal.prototype.applyHeaderWidths = function (columnWidths) {
        var self = this;

        this.$tableHead.find('th').each(function (index, th) {
            self.setElementWidth($(th), columnWidths[index]);
        });
    };

    PreviewModal.prototype.setElementWidth = function ($element, width) {
        var normalized = parseInt(width, 10);

        if (isNaN(normalized) || normalized <= 0) {
            return;
        }

        var widthPx = normalized + 'px';

        $element.css({
            width: widthPx,
            minWidth: widthPx,
            maxWidth: widthPx
        });
    };

    PreviewModal.prototype.updateTableWidth = function (columnWidths) {
        if (!this.$table.length || !Array.isArray(columnWidths) || !columnWidths.length) {
            return;
        }

        var totalWidth = columnWidths.reduce(function (sum, width) {
            var normalized = parseInt(width, 10);

            if (isNaN(normalized) || normalized <= 0) {
                return sum;
            }

            return sum + normalized;
        }, 0);

        if (totalWidth > 0) {
            var widthPx = totalWidth + 'px';

            this.$table.css({
                width: widthPx,
                minWidth: widthPx,
                maxWidth: widthPx
            });
        } else {
            this.$table.css('width', 'auto');
        }
    };

    PreviewModal.prototype.buildColumnsFromRow = function (row) {
        if (!row || typeof row !== 'object') {
            return [];
        }

        return Object.keys(row).map(function (key) {
            return {
                key: key,
                label: key,
                private: false
            };
        });
    };

    PreviewModal.prototype.formatString = function (template, value) {
        if (!template) {
            return '';
        }

        return template.replace('%1$s', value);
    };

    PreviewModal.prototype.serializeForm = function () {
        var data = {};

        this.$form.serializeArray().forEach(function (entry) {
            var name = entry.name;
            var value = entry.value;

            if (name.slice(-2) === '[]') {
                data[name] = data[name] || [];
                data[name].push(value);
                return;
            }

            if (Object.prototype.hasOwnProperty.call(data, name)) {
                if (!Array.isArray(data[name])) {
                    data[name] = [data[name]];
                }

                data[name].push(value);
                return;
            }

            data[name] = value;
        });

        return data;
    };

    PreviewModal.prototype.getString = function (key) {
        if (!this.strings || !Object.prototype.hasOwnProperty.call(this.strings, key)) {
            return '';
        }

        return this.strings[key];
    };

    function TemplateUI(options) {
        this.$form = options.form;
        this.ajax = options.ajax || {};
        this.strings = options.strings || {};
        this.templates = {};
        this.currentTemplateId = options.selected || '';
        this.$panel = this.$form.find('[data-template-panel]');
        this.$select = this.$panel.find('[data-template-select]');
        this.$description = this.$panel.find('[data-template-description]');
        this.$status = this.$panel.find('[data-template-status]');
        this.$modal = this.$form.closest('.wooproduct-exporter').find('[data-template-modal]');
        this.$modalForm = this.$modal.find('[data-template-modal-form]');
        this.$modalTitle = this.$modal.find('[data-template-modal-title]');
        this.$modalSubmit = this.$modal.find('[data-template-modal-submit]');
        this.$attachZipToggle = this.$form.find('[name="export_attach_images_zip"]');
        this.$modalAttachZip = this.$modal.find('[data-template-attach-images-zip]');
        this.modalMode = 'create';
        this.conditionBuilder = options.conditionBuilder || null;
        this.fieldOrdering = options.fieldOrdering || null;
        this.$conditionInput = this.$form.find('[data-condition-builder-input]');
        this.$dropzone = this.$panel.find('[data-template-dropzone]');
        this.$importInput = this.$panel.find('[data-template-import-input]');
        this.$importReplace = this.$panel.find('[data-template-import-replace]');
        this.importHoverClass = 'is-hovered';
        this.dragCounter = 0;

        this.initTemplates(options.templates || []);
        this.bindEvents();
    }

    TemplateUI.prototype.initTemplates = function (items) {
        var self = this;
        items.forEach(function (item) {
            if (!item || !item.id) {
                return;
            }

            self.templates[item.id] = item;
        });

        this.renderTemplateOptions();
        this.updateDescription();
    };

    TemplateUI.prototype.bindEvents = function () {
        var self = this;

        this.$select.on('change', function () {
            if (self.isApplying) {
                return;
            }

            var templateId = $(this).val();
            self.currentTemplateId = templateId;
            self.updateDescription();
            if (templateId && self.templates[templateId]) {
                self.applyTemplate(self.templates[templateId]);
            }

            self.persistSelection(templateId);
        });

        this.$panel.find('[data-template-save]').on('click', function (event) {
            event.preventDefault();
            self.openModal('create');
        });

        this.$panel.find('[data-template-update]').on('click', function (event) {
            event.preventDefault();
            if (!self.ensureTemplateSelected()) {
                return;
            }

            self.openModal('update');
        });

        this.$panel.find('[data-template-delete]').on('click', function (event) {
            event.preventDefault();
            self.deleteTemplate();
        });

        this.$panel.find('[data-template-export]').on('click', function (event) {
            event.preventDefault();
            self.exportTemplate();
        });

        this.$panel.find('[data-template-import-trigger]').on('click', function (event) {
            event.preventDefault();
            self.$importInput.trigger('click');
        });

        this.$importInput.on('change', function () {
            if (this.files && this.files.length) {
                self.importTemplateFile(this.files[0]);
                self.$importInput.val('');
            }
        });

        this.$modal.find('[data-template-modal-close], [data-template-modal-cancel]').on('click', function (event) {
            event.preventDefault();
            self.closeModal();
        });

        this.$modalForm.on('submit', function (event) {
            event.preventDefault();
            self.syncModalAttachZipToForm();
            self.handleModalSubmit();
        });

        if (this.$modalAttachZip.length) {
            this.$modalAttachZip.on('change', function () {
                self.syncModalAttachZipToForm();
            });
        }

        this.$dropzone.on('dragenter dragover', function (event) {
            event.preventDefault();
            event.stopPropagation();
            self.dragCounter++;
            self.$dropzone.addClass(self.importHoverClass);
        });

        this.$dropzone.on('dragleave', function (event) {
            event.preventDefault();
            event.stopPropagation();
            self.dragCounter--;
            if (self.dragCounter <= 0) {
                self.$dropzone.removeClass(self.importHoverClass);
            }
        });

        this.$dropzone.on('drop', function (event) {
            event.preventDefault();
            event.stopPropagation();
            self.dragCounter = 0;
            self.$dropzone.removeClass(self.importHoverClass);

            var files = event.originalEvent.dataTransfer ? event.originalEvent.dataTransfer.files : null;

            if (files && files.length) {
                self.importTemplateFile(files[0]);
            }
        });
    };

    TemplateUI.prototype.renderTemplateOptions = function () {
        var options = '<option value="">' + (this.strings.noTemplateOption || '—') + '</option>';
        var keys = Object.keys(this.templates).sort(function (a, b) {
            return this.templates[a].name.localeCompare(this.templates[b].name, undefined, { sensitivity: 'base' });
        }.bind(this));

        keys.forEach(function (id) {
            var template = this.templates[id];
            options += '<option value="' + id + '">' + template.name + '</option>';
        }, this);

        this.$select.html(options);
        if (this.currentTemplateId) {
            this.isApplying = true;
            this.$select.val(this.currentTemplateId);
            this.isApplying = false;
        }
    };

    TemplateUI.prototype.openModal = function (mode) {
        this.modalMode = mode || 'create';
        var template = this.templates[this.currentTemplateId] || {};
        var isUpdate = 'update' === this.modalMode;
        var title = isUpdate ? (this.strings.modalUpdateTitle || 'Update template') : (this.strings.modalCreateTitle || 'Save template');
        var button = isUpdate ? (this.strings.modalUpdateButton || 'Update template') : (this.strings.modalSaveButton || 'Save template');

        this.$modalTitle.text(title);
        this.$modalSubmit.text(button);
        this.$modal.find('input[name="template_name"]').val(isUpdate ? template.name : '');
        this.$modal.find('textarea[name="template_description"]').val(isUpdate ? template.description : '');
        if (this.$modalAttachZip.length) {
            this.$modalAttachZip.prop('checked', this.$attachZipToggle.is(':checked'));
        }
        this.$modal.removeAttr('hidden');
    };

    TemplateUI.prototype.closeModal = function () {
        this.$modal.attr('hidden', true);
        this.$modalForm[0].reset();
    };

    TemplateUI.prototype.handleModalSubmit = function () {
        var name = this.$modal.find('input[name="template_name"]').val();
        var description = this.$modal.find('textarea[name="template_description"]').val();

        if (!name) {
            this.setStatus(this.strings.errorNameRequired || this.strings.errorNoTemplate || 'Template name is required.', true);
            return;
        }

        if ('update' === this.modalMode) {
            this.saveTemplate('update', { name: name, description: description });
        } else {
            this.saveTemplate('create', { name: name, description: description });
        }
    };

    TemplateUI.prototype.saveTemplate = function (mode, meta) {
        var actionKey = 'create' === mode ? 'create' : 'update';
        var action = this.ajax.actions ? this.ajax.actions[actionKey] : null;

        if (!action) {
            return;
        }

        if ('update' === mode && !this.ensureTemplateSelected()) {
            return;
        }

        var payload = this.serializeFormObject();
        payload.template_name = meta.name;
        payload.template_description = meta.description;
        payload.action = action;
        payload.nonce = this.ajax.nonce;

        if ('update' === mode) {
            payload.template_id = this.currentTemplateId;
        }

        var self = this;
        $.ajax({
            url: this.ajax.url,
            method: 'POST',
            data: payload,
        })
            .done(function (response) {
                if (!response || !response.success || !response.data) {
                    self.handleAjaxError(response);
                    return;
                }

                var template = response.data.data || {};

                if (!template.id) {
                    self.setStatus(self.strings.errorTemplateMissing || self.strings.errorNoTemplate || 'Template data missing.', true);
                    return;
                }

                self.templates[template.id] = template;
                self.currentTemplateId = template.id;
                self.renderTemplateOptions();
                self.applyTemplate(template);
                self.closeModal();
                self.setStatus('update' === mode ? (self.strings.toastUpdated || 'Template updated.') : (self.strings.toastSaved || 'Template saved.'));
            })
            .fail(function (jqXHR) {
                self.handleAjaxError(jqXHR);
            });
    };

    TemplateUI.prototype.deleteTemplate = function () {
        if (!this.ensureTemplateSelected()) {
            return;
        }

        if (!window.confirm(this.strings.confirmDelete || 'Delete the selected template?')) {
            return;
        }

        var action = this.ajax.actions ? this.ajax.actions.delete : null;
        if (!action) {
            return;
        }

        var self = this;
        $.ajax({
            url: this.ajax.url,
            method: 'POST',
            data: {
                action: action,
                nonce: this.ajax.nonce,
                template_id: this.currentTemplateId,
            },
        })
            .done(function (response) {
                if (!response || !response.success) {
                    self.handleAjaxError(response);
                    return;
                }

                delete self.templates[self.currentTemplateId];
                self.currentTemplateId = '';
                self.renderTemplateOptions();
                self.updateDescription();
                self.setStatus(self.strings.toastDeleted || 'Template deleted.');
            })
            .fail(function (jqXHR) {
                self.handleAjaxError(jqXHR);
            });
    };

    TemplateUI.prototype.exportTemplate = function () {
        if (!this.ensureTemplateSelected()) {
            return;
        }

        var action = this.ajax.actions ? this.ajax.actions.export : null;
        if (!action) {
            return;
        }

        var $tempForm = $('<form>', {
            method: 'post',
            action: this.ajax.url,
            target: '_blank',
        });

        $tempForm.append($('<input>', { type: 'hidden', name: 'action', value: action }));
        $tempForm.append($('<input>', { type: 'hidden', name: 'nonce', value: this.ajax.nonce }));
        $tempForm.append($('<input>', { type: 'hidden', name: 'template_id', value: this.currentTemplateId }));

        $tempForm.appendTo('body').trigger('submit').remove();
    };

    TemplateUI.prototype.importTemplateFile = function (file) {
        if (!file) {
            this.setStatus(this.strings.errorNoFile || 'Select a CSV file to import.', true);
            return;
        }

        if (!/\.csv$/i.test(file.name)) {
            this.setStatus(this.strings.errorInvalidFile || 'Only CSV templates are supported.', true);
            return;
        }

        var action = this.ajax.actions ? this.ajax.actions.import : null;
        if (!action) {
            return;
        }

        var formData = new window.FormData();
        formData.append('action', action);
        formData.append('nonce', this.ajax.nonce);
        formData.append('template_file', file);
        formData.append('replace_existing', this.$importReplace.is(':checked') ? '1' : '');

        var self = this;
        $.ajax({
            url: this.ajax.url,
            method: 'POST',
            data: formData,
            processData: false,
            contentType: false,
        })
            .done(function (response) {
                if (!response || !response.success || !response.data) {
                    self.handleAjaxError(response);
                    return;
                }

                var imported = response.data.templates || [];
                var importedFirst = null;
                var updatedCurrent = false;

                imported.forEach(function (entry) {
                    if (!entry || !entry.data || !entry.data.id) {
                        return;
                    }

                    self.templates[entry.data.id] = entry.data;
                    if (!importedFirst) {
                        importedFirst = entry.data.id;
                    }

                    if (entry.data.id === self.currentTemplateId) {
                        updatedCurrent = true;
                    }
                });

                self.renderTemplateOptions();

                if (updatedCurrent && self.templates[self.currentTemplateId]) {
                    self.applyTemplate(self.templates[self.currentTemplateId]);
                } else if (importedFirst && self.templates[importedFirst]) {
                    self.applyTemplate(self.templates[importedFirst]);
                    self.persistSelection(importedFirst);
                }

                self.setStatus(self.strings.toastImported || 'Templates imported.');
            })
            .fail(function (jqXHR) {
                self.handleAjaxError(jqXHR);
            });
    };

    TemplateUI.prototype.applyTemplate = function (template) {
        if (!template) {
            return;
        }

        this.isApplying = true;
        this.$select.val(template.id || '');
        this.currentTemplateId = template.id || '';
        this.updateDescription();

        this.applyFields(template.fields || []);
        this.applyFormat(template.format);
        this.applyFileSettings(template.settings || {});
        this.applyFilters(template.filters || {});

        this.isApplying = false;
        this.setStatus(this.strings.statusApplied || 'Template applied.');
    };

    TemplateUI.prototype.applyFields = function (fields) {
        var $checkboxes = this.$form.find('input[name="fields[]"]');
        $checkboxes.prop('checked', false);

        fields.forEach(function (field) {
            $checkboxes.filter('[value="' + field + '"]').prop('checked', true);
        });

        if (this.fieldOrdering && typeof this.fieldOrdering.applySelection === 'function') {
            this.fieldOrdering.applySelection(fields);
        }
    };

    TemplateUI.prototype.applyFormat = function (format) {
        if (!format) {
            return;
        }

        this.$form.find('select[name="export_format"]').val(format);
    };

    TemplateUI.prototype.applyFileSettings = function (settings) {
        settings = settings || {};
        this.$form.find('[name="export_delimiter"]').val(settings.delimiter || ',');
        this.$form.find('[name="export_encoding"]').val(settings.encoding || 'UTF-8');
        this.$form.find('[name="export_filename"]').val(settings.filename || 'wc-products-export-{{date}}');
        if (this.$attachZipToggle && this.$attachZipToggle.length) {
            this.$attachZipToggle.prop('checked', !!settings.attach_images_zip);
        }
    };

    TemplateUI.prototype.syncModalAttachZipToForm = function () {
        if (!this.$modalAttachZip.length || !this.$attachZipToggle.length) {
            return;
        }

        this.$attachZipToggle.prop('checked', this.$modalAttachZip.is(':checked'));
    };

    TemplateUI.prototype.applyFilters = function (filters) {
        filters = filters || {};

        this.setSelect('filter_category', filters.category || '0');
        this.setSelect('filter_brand', filters.brand || '0');
        this.setRange('filter_regular_price', filters.price && filters.price.regular ? filters.price.regular : {});
        this.setRange('filter_sale_price', filters.price && filters.price.sale ? filters.price.sale : {});
        this.setStockFilters(filters.stock || {});
        this.setDateRange('filter_created', filters.date_created || {});
        this.setDateRange('filter_modified', filters.date_modified || {});
        this.setSelect('filter_discount_mode', filters.discount_mode || '');
        this.setSelect('filter_image_mode', filters.image_mode || '');
        this.setSelect('filter_reviews_mode', filters.reviews_mode || '');
        this.setInput('filter_description_search', filters.description_search || '');
        this.setMultiSelect('filter_exclude_categories[]', filters.exclude_categories || []);
        this.setMultiSelect('filter_exclude_tags[]', filters.exclude_tags || []);
        this.setConditionGroups(filters.condition_groups || {});
    };

    TemplateUI.prototype.setRange = function (prefix, range) {
        this.setInput(prefix + '_min', range.min != null ? range.min : '');
        this.setInput(prefix + '_max', range.max != null ? range.max : '');
    };

    TemplateUI.prototype.setStockFilters = function (stock) {
        this.setInput('filter_stock_min', stock.min != null ? stock.min : '');
        this.setInput('filter_stock_max', stock.max != null ? stock.max : '');
        this.setCheckbox('filter_stock_only_in_stock', stock.only_in_stock);
        this.setCheckbox('filter_stock_only_zero', stock.only_zero);
    };

    TemplateUI.prototype.setDateRange = function (prefix, range) {
        this.setInput(prefix + '_from', range.from || '');
        this.setInput(prefix + '_to', range.to || '');
    };

    TemplateUI.prototype.setConditionGroups = function (state) {
        var json = JSON.stringify(state || {});
        this.$conditionInput.val(json);

        if (this.conditionBuilder && typeof this.conditionBuilder.setState === 'function') {
            this.conditionBuilder.setState(state);
        }
    };

    TemplateUI.prototype.setSelect = function (name, value) {
        this.$form.find('[name="' + name + '"]').val(value);
    };

    TemplateUI.prototype.setInput = function (name, value) {
        this.$form.find('[name="' + name + '"]').val(value);
    };

    TemplateUI.prototype.setCheckbox = function (name, checked) {
        this.$form.find('[name="' + name + '"]').prop('checked', !!checked);
    };

    TemplateUI.prototype.setMultiSelect = function (name, values) {
        var $input = this.$form.find('[name="' + name + '"]');
        var normalized = (values || []).map(function (value) {
            return String(value);
        });

        $input.val(normalized);
    };

    TemplateUI.prototype.serializeFormObject = function () {
        var data = {};

        this.$form.serializeArray().forEach(function (entry) {
            var name = entry.name;
            var value = entry.value;

            if (name.slice(-2) === '[]') {
                name = name.slice(0, -2) + '[]';
                data[name] = data[name] || [];
                data[name].push(value);
            } else if (data[name] !== undefined) {
                if (!Array.isArray(data[name])) {
                    data[name] = [data[name]];
                }

                data[name].push(value);
            } else {
                data[name] = value;
            }
        });

        return data;
    };

    TemplateUI.prototype.ensureTemplateSelected = function () {
        if (!this.currentTemplateId || !this.templates[this.currentTemplateId]) {
            this.setStatus(this.strings.errorNoTemplate || 'Select a template first.', true);
            return false;
        }

        return true;
    };

    ScheduleModal.prototype.normalizeWeeklyCustomPayload = function () {
        var modeMap = {};
        var hasTimes = false;

        this.state.weeklyDays.forEach(function (day) {
            var list = this.state.weeklyTimesByDay[day];
            var normalized = Array.isArray(list) ? list.filter(function (value) {
                return !!value;
            }) : [];

            if (!normalized.length) {
                return;
            }

            modeMap[day] = normalized.slice(0);
            hasTimes = true;
        }, this);

        if (!hasTimes) {
            return null;
        }

        return {
            timesByDay: modeMap,
            sharedTimes: [],
        };
    };

    TemplateUI.prototype.persistSelection = function (templateId) {
        var action = this.ajax.actions ? this.ajax.actions.select : null;
        if (!action) {
            return;
        }

        $.post(this.ajax.url, {
            action: action,
            nonce: this.ajax.nonce,
            template_id: templateId || '',
        });
    };

    TemplateUI.prototype.updateDescription = function () {
        var template = this.currentTemplateId ? this.templates[this.currentTemplateId] : null;
        if (!template) {
            this.$description.text('');
            return;
        }

        var desc = template.description || '';
        if (template.updated_at) {
            desc += (desc ? ' · ' : '') + template.updated_at;
        }

        this.$description.text(desc);
    };

    TemplateUI.prototype.setStatus = function (message, isError) {
        if (!message) {
            this.$status.attr('hidden', true).text('');
            return;
        }

        this.$status.text(message).toggleClass('is-error', !!isError).attr('hidden', false);

        var self = this;
        clearTimeout(this.statusTimer);
        this.statusTimer = window.setTimeout(function () {
            self.$status.attr('hidden', true).text('');
        }, 4000);
    };

    TemplateUI.prototype.handleAjaxError = function (response) {
        var message = (response && response.responseJSON && response.responseJSON.data && response.responseJSON.data.message)
            || (response && response.data && response.data.message)
            || this.strings.genericError
            || 'Something went wrong.';
        this.setStatus(message, true);
    };

    function ScheduleModal($modal) {
        this.$modal = $modal;

        if (!this.$modal || !this.$modal.length) {
            this.isReady = false;
            return;
        }

        this.$form = this.$modal.find('[data-schedule-form]');
        this.$title = this.$modal.find('[data-schedule-modal-title]');
        this.$submit = this.$modal.find('[data-schedule-submit]');
        this.$modeRadios = this.$form.find('[name="schedule_mode"]');
        this.$automaticTypeRadios = this.$form.find('[name="automatic_type"]');
        this.$panels = this.$form.find('[data-schedule-panel]');
        this.$automaticFields = this.$form.find('[data-automatic]');
        this.$weeklyDaysContainer = this.$form.find('[data-weekly-days]');
        this.$weeklyTimesContainer = this.$form.find('[data-weekly-times]');
        this.$weeklyTimeInput = this.$form.find('[data-weekly-time-input]');
        this.$weeklyTimeAdd = this.$form.find('[data-weekly-time-add]');
        this.$weeklySharedGroup = this.$form.find('[data-weekly-shared]');
        this.$weeklyCustomGroup = this.$form.find('[data-weekly-custom]');
        this.$weeklyCustomContainer = this.$form.find('[data-weekly-custom-container]');
        this.$weeklyCustomEmpty = this.$form.find('[data-weekly-custom-empty]');
        this.$weeklyCustomDisplay = this.$form.find('[data-weekly-custom-display]');
        this.$weeklyCustomHeading = this.$form.find('[data-weekly-custom-heading]');
        this.$weeklyCustomTimes = this.$form.find('[data-weekly-custom-times]');
        this.$weeklyCustomTimeInput = this.$form.find('[data-weekly-custom-time-input]');
        this.$weeklyCustomAddButton = this.$form.find('[data-weekly-custom-add]');
        this.$weeklyCustomRemoveDayButton = this.$form.find('[data-weekly-custom-remove-day]');
        this.$weeklyModeLabel = this.$form.find('[data-weekly-mode-label]');
        this.$monthlyDayInput = this.$form.find('[data-monthly-day]');
        this.$monthlyTimesContainer = this.$form.find('[data-monthly-times]');
        this.$monthlyTimeInput = this.$form.find('[data-monthly-time-input]');
        this.$monthlyTimeAdd = this.$form.find('[data-monthly-time-add]');
        this.$timezone = this.$form.find('[name="task_timezone"]');
        this.$cronInput = this.$form.find('[name="task_cron_expression"]');
        this.$payloadInput = this.$form.find('[data-schedule-payload]');
        this.$typeInput = this.$form.find('[data-schedule-type]');
        this.$intervalInput = this.$form.find('[data-schedule-interval]');
        this.$enabledInput = this.$form.find('[data-schedule-enabled]');
        this.$taskIdInput = this.$form.find('[data-schedule-task-id]');
        this.$nameInput = this.$form.find('#schedule_task_name');
        this.$templateSelect = this.$form.find('#schedule_task_template');
        this.$incrementalToggle = this.$form.find('[name="task_incremental"]');
        this.$incrementalField = this.$form.find('[name="task_incremental_field"]');
        this.$actionsContainer = this.$form.find('[data-actions-container]');
        this.$actionsEmptyNotice = this.$form.find('[data-actions-empty]');
        this.$actionsAddButton = this.$form.find('[data-action-add]');
        this.$actionsPayloadInput = this.$form.find('[data-actions-payload]');
        this.$actionEditor = this.$form.find('[data-action-editor]');
        this.$actionTypeSelect = this.$actionEditor.find('[data-action-type]');
        this.$actionConfigContainer = this.$actionEditor.find('[data-action-config]');
        this.$actionSaveButton = this.$actionEditor.find('[data-action-save]');
        this.$closers = this.$modal.find('[data-schedule-modal-close]');
        this.$document = $(document);

        var parseIntSafe = function (input) {
            var value = parseInt(input, 10);
            return isNaN(value) ? null : value;
        };

        this.weekdayLabels = this.parseWeekdayLabels(this.$weeklyDaysContainer.attr('data-weekday-labels'));

        this.defaults = {
            timezone: this.$modal.data('default-timezone') || 'UTC',
            weekday: parseIntSafe(this.$modal.data('default-weekday')),
            time: this.normalizeTime(String(this.$modal.data('default-time') || '')),
            monthDay: parseIntSafe(this.$modal.data('default-monthly-day')) || 1,
        };

        this.wpTimezone = this.defaults.timezone;
        this.browserTimezone = this.detectBrowserTimezone();

        // Use WordPress timezone if available in dropdown, otherwise fallback to browser timezone
        if (this.wpTimezone && this.isTimezoneOptionAvailable(this.wpTimezone)) {
            this.defaults.timezone = this.wpTimezone;
        } else if (this.browserTimezone) {
            this.defaults.timezone = this.browserTimezone;
        }

        if (this.defaults.weekday === null) {
            this.defaults.weekday = 1;
        }

        var browserTime = this.detectLocalTime();

        if (browserTime) {
            this.defaults.time = browserTime;
        } else if (!this.defaults.time) {
            this.defaults.time = '09:00';
        }

        this.state = {
            weeklyDays: [],
            weeklyTimes: [],
            weeklyMode: 'shared',
            weeklyTimesByDay: {},
            weeklyActiveDay: null,
            monthlyDay: this.defaults.monthDay,
            monthlyTimes: [],
            actions: [],
            actionDraft: null,
        };

        this.isReady = true;
        this.isOpen = false;
        this.isEditing = false;
        this.currentTaskId = 0;
        this.editData = null;
        this.isEditingAction = false;
        this.editingActionIndex = -1;

        this.handleKeydown = this.handleKeydown.bind(this);

        this.strings = (window.WCPCE_Admin && window.WCPCE_Admin.scheduleConfig && window.WCPCE_Admin.scheduleConfig.strings) || {};
        this.alerts = (window.WCPCE_Admin && window.WCPCE_Admin.scheduleConfig && window.WCPCE_Admin.scheduleConfig.alerts) || {};
        this.actionDefinitions = (window.WCPCE_Admin && window.WCPCE_Admin.scheduleConfig && window.WCPCE_Admin.scheduleConfig.actionDefinitions) || {};
        this.actionLabels = (window.WCPCE_Admin && window.WCPCE_Admin.scheduleConfig && window.WCPCE_Admin.scheduleConfig.actionLabels) || {};
        this.init();
    }

    ScheduleModal.prototype.init = function () {
        if (!this.isReady) {
            return;
        }

        this.bindEvents();
        this.resetForm();
    };

    ScheduleModal.prototype.detectBrowserTimezone = function () {
        if (!this.$timezone || !this.$timezone.length || !window.Intl || !Intl.DateTimeFormat) {
            return null;
        }

        var resolvedOptions;

        try {
            resolvedOptions = Intl.DateTimeFormat().resolvedOptions();
        } catch (error) {
            resolvedOptions = null;
        }

        var timezone = resolvedOptions && resolvedOptions.timeZone ? resolvedOptions.timeZone : null;

        if (!timezone || !this.isTimezoneOptionAvailable(timezone)) {
            return null;
        }

        return timezone;
    };

    ScheduleModal.prototype.isTimezoneOptionAvailable = function (timezone) {
        if (!timezone || !this.$timezone || !this.$timezone.length) {
            return false;
        }

        return this.$timezone.find('option').filter(function () {
            return $(this).val() === timezone;
        }).length > 0;
    };

    ScheduleModal.prototype.detectLocalTime = function () {
        var now = new Date();

        if (isNaN(now.getTime())) {
            return null;
        }

        var pad = function (value) {
            return value < 10 ? '0' + value : String(value);
        };

        return pad(now.getHours()) + ':' + pad(now.getMinutes());
    };

    ScheduleModal.prototype.bindEvents = function () {
        var self = this;

        this.$document.on('click', '[data-schedule-modal-open]', function (event) {
            event.preventDefault();
            self.open();
        });

        this.$closers.on('click', function (event) {
            event.preventDefault();
            self.close();
        });

        this.$modal.on('click', function (event) {
            if (event.target === self.$modal.get(0)) {
                self.close();
            }
        });

        this.$form.on('submit', function (event) {
            if (!self.prepareSubmission()) {
                event.preventDefault();
            }
        });

        this.$modeRadios.on('change', function () {
            self.updatePanels();
            self.updateEnabledField();
        });

        this.$automaticTypeRadios.on('change', function () {
            self.updateAutomaticFields();
        });

        this.$weeklyDaysContainer.on('click', 'button', function (event) {
            event.preventDefault();
            var day = parseInt($(this).data('day'), 10);

            if (isNaN(day)) {
                return;
            }

            var wasActive = self.isWeeklyDaySelected(day);
            self.toggleWeeklyDay(day);

            if (self.state.weeklyMode === 'per_day') {
                if (wasActive) {
                    if (self.state.weeklyActiveDay === day) {
                        self.state.weeklyActiveDay = null;
                    }
                } else {
                    self.state.weeklyActiveDay = day;
                }

                self.renderWeeklyCustom();
            }
        });

        this.$weeklyTimeAdd.on('click', function (event) {
            event.preventDefault();
            self.addWeeklyTime(self.$weeklyTimeInput.val());
        });

        this.$weeklyTimesContainer.on('click', '[data-time-chip]', function (event) {
            event.preventDefault();
            var value = $(this).data('time');
            self.removeWeeklyTime(value);
        });

        this.$weeklyCustomAddButton.on('click', function (event) {
            event.preventDefault();

            if (self.state.weeklyActiveDay === null) {
                return;
            }

            self.addWeeklyCustomTime(self.state.weeklyActiveDay, self.$weeklyCustomTimeInput.val());
            self.updateWeeklyCustomDisplay();
        });

        this.$weeklyCustomTimes.on('click', '[data-weekly-custom-chip]', function (event) {
            event.preventDefault();
            var value = $(this).data('time');

            if (!value || self.state.weeklyActiveDay === null) {
                return;
            }

            self.removeWeeklyCustomTime(self.state.weeklyActiveDay, value);
            self.updateWeeklyCustomDisplay();
        });

        this.$weeklyCustomRemoveDayButton.on('click', function (event) {
            event.preventDefault();

            if (self.state.weeklyActiveDay === null) {
                return;
            }

            self.removeWeeklyDay(self.state.weeklyActiveDay);
        });

        this.$monthlyTimeAdd.on('click', function (event) {
            event.preventDefault();
            self.addTime('monthly', self.$monthlyTimeInput.val());
        });

        this.$monthlyTimesContainer.on('click', '[data-time-chip]', function (event) {
            event.preventDefault();
            var value = $(this).data('time');
            self.removeTime('monthly', value);
        });

        this.$monthlyDayInput.on('input change', function () {
            var value = parseInt($(this).val(), 10);

            if (isNaN(value)) {
                return;
            }

            value = Math.min(Math.max(value, 1), 31);
            self.state.monthlyDay = value;
            $(this).val(value);
        });

        this.$incrementalToggle.on('change', function () {
            self.updateIncrementalVisibility();
        });

        this.$actionsAddButton.on('click', function (event) {
            event.preventDefault();
            self.openActionModal();
        });

        this.$actionEditor.find('[data-action-cancel]').on('click', function (event) {
            event.preventDefault();
            self.closeActionModal();
        });

        this.$actionTypeSelect.on('change', function () {
            if (!self.state.actionDraft) {
                return;
            }

            self.state.actionDraft.type = $(this).val();
            self.state.actionDraft.config = {};
            self.renderActionConfigFields(self.state.actionDraft.type, self.state.actionDraft.config);
        });

        this.$actionSaveButton.on('click', function (event) {
            event.preventDefault();
            self.saveActionDraft();
        });

        this.$actionsContainer.on('click', '[data-action-edit]', function (event) {
            event.preventDefault();
            var index = parseInt($(this).closest('[data-action-index]').data('action-index'), 10);

            if (isNaN(index)) {
                return;
            }

            self.editAction(index);
        });

        this.$actionsContainer.on('click', '[data-action-remove]', function (event) {
            event.preventDefault();
            var index = parseInt($(this).closest('[data-action-index]').data('action-index'), 10);

            if (isNaN(index)) {
                return;
            }

            self.removeAction(index);
        });

        $(document).on('click', '[data-schedule-edit]', function (event) {
            event.preventDefault();
            var raw = $(this).attr('data-schedule-edit');
            var data = self.parseEditData(raw);

            if (!data) {
                window.alert(self.alerts.loadFailed || 'Unable to load schedule data.');
                return;
            }

            self.open(data);
        });
    };

    ScheduleModal.prototype.resetForm = function () {
        if (this.$form.length && this.$form.get(0)) {
            this.$form.get(0).reset();
        }

        this.state.weeklyDays = [];
        this.state.weeklyTimes = [];
        this.state.monthlyTimes = [];
        this.state.weeklyMode = 'shared';
        this.state.weeklyTimesByDay = {};
        this.state.weeklyActiveDay = null;
        this.state.monthlyDay = this.defaults.monthDay;
        this.state.actions = [];
        this.state.actionDraft = null;
        this.isEditing = false;
        this.currentTaskId = 0;
        this.editData = null;
        this.isEditingAction = false;
        this.editingActionIndex = -1;

        if (!isNaN(this.defaults.weekday)) {
            this.state.weeklyDays.push(this.defaults.weekday);
        }

        this.$weeklyTimeInput.val(this.defaults.time);
        this.updateWeeklyModeLabel();
        this.$monthlyTimeInput.val(this.defaults.time);
        this.$monthlyDayInput.val(this.state.monthlyDay);

        var timezoneValue = this.defaults.timezone;

        if (!this.isTimezoneOptionAvailable(timezoneValue) && this.wpTimezone && this.isTimezoneOptionAvailable(this.wpTimezone)) {
            timezoneValue = this.wpTimezone;
        }

        if (timezoneValue) {
            this.$timezone.val(timezoneValue);
        } else if (this.$timezone && this.$timezone.length) {
            this.$timezone.prop('selectedIndex', 0);
        }

        this.$modeRadios.filter('[value="automatic"]').prop('checked', true);
        this.$automaticTypeRadios.filter('[value="weekly"]').prop('checked', true);
        this.$cronInput.val('');
        this.$taskIdInput.val('');
        this.$nameInput.val('');
        this.$templateSelect.val('');
        this.$incrementalToggle.prop('checked', false);
        this.$incrementalField.val('post_modified');
        this.$enabledInput.val(1);
        this.$actionsPayloadInput.val('[]');

        this.renderWeeklyDays();
        this.renderWeeklyMode();
        this.renderTimes('monthly');
        this.renderActions();
        this.updatePanels();
        this.updateAutomaticFields();
        this.updateEnabledField();
        this.updateIncrementalVisibility();

        this.closeActionModal(true);
    };

    ScheduleModal.prototype.open = function (taskData) {
        if (!this.isReady) {
            return;
        }

        this.resetForm();

        if (taskData && typeof taskData === 'object') {
            this.populateForm(taskData);
            this.isEditing = true;
            this.currentTaskId = taskData.id || 0;
            this.updateModalLabels('edit');
        } else {
            this.updateModalLabels('create');
        }

        this.$modal.removeAttr('hidden');
        $('body').addClass('wc-pce-modal-open');
        this.isOpen = true;
        this.$document.on('keydown', this.handleKeydown);

        var self = this;
        if (this.$nameInput && this.$nameInput.length) {
            window.setTimeout(function () {
                self.$nameInput.trigger('focus');
            }, 20);
        }
    };

    ScheduleModal.prototype.close = function () {
        if (!this.isOpen) {
            return;
        }

        this.$modal.attr('hidden', true);
        $('body').removeClass('wc-pce-modal-open');
        this.isOpen = false;
        this.$document.off('keydown', this.handleKeydown);
        this.isEditing = false;
        this.currentTaskId = 0;
        this.editData = null;
        this.updateModalLabels('create');
    };

    ScheduleModal.prototype.handleKeydown = function (event) {
        if ('Escape' === event.key || 27 === event.keyCode) {
            this.close();
        }
    };

    ScheduleModal.prototype.getMode = function () {
        return this.$modeRadios.filter(':checked').val() || 'automatic';
    };

    ScheduleModal.prototype.getAutomaticType = function () {
        return this.$automaticTypeRadios.filter(':checked').val() || 'weekly';
    };

    ScheduleModal.prototype.updatePanels = function () {
        var mode = this.getMode();

        this.$panels.each(function () {
            var $panel = $(this);
            var panelMode = $panel.data('schedule-panel');
            var isVisible = panelMode === mode;
            $panel.attr('hidden', !isVisible);
        });
    };

    ScheduleModal.prototype.updateAutomaticFields = function () {
        var type = this.getAutomaticType();

        this.$automaticFields.each(function () {
            var $field = $(this);
            var fieldType = $field.data('automatic');
            $field.attr('hidden', fieldType !== type);
        });
    };

    ScheduleModal.prototype.updateEnabledField = function () {
        var mode = this.getMode();
        var enabled = 'none' === mode ? 0 : 1;
        this.$enabledInput.val(enabled);
    };

    ScheduleModal.prototype.toggleWeeklyDay = function (day) {
        var index = this.state.weeklyDays.indexOf(day);

        if (index === -1) {
            this.state.weeklyDays.push(day);
        } else {
            this.state.weeklyDays.splice(index, 1);
        }

        this.state.weeklyDays.sort(function (a, b) {
            return a - b;
        });

        this.renderWeeklyDays();

        if (this.state.weeklyMode === 'per_day') {
            if (this.state.weeklyActiveDay === day) {
                this.state.weeklyActiveDay = null;
            }

            this.cleanupWeeklyCustomDay(day);
            this.renderWeeklyCustom();
        }

        this.evaluateWeeklyMode();
    };

    ScheduleModal.prototype.isWeeklyDaySelected = function (day) {
        return this.state.weeklyDays.indexOf(day) !== -1;
    };

    ScheduleModal.prototype.renderWeeklyDays = function () {
        var self = this;

        this.$weeklyDaysContainer.find('button').each(function () {
            var $button = $(this);
            var day = parseInt($button.data('day'), 10);
            var isActive = self.state.weeklyDays.indexOf(day) !== -1;

            $button.toggleClass('is-active', isActive);
        });
    };

    ScheduleModal.prototype.normalizeTime = function (value) {
        if (!value) {
            return '';
        }

        var match = String(value).match(/^(\d{1,2}):(\d{2})$/);

        if (!match) {
            return '';
        }

        var hours = Math.min(23, Math.max(0, parseInt(match[1], 10)));
        var minutes = Math.min(59, Math.max(0, parseInt(match[2], 10)));

        return ('0' + hours).slice(-2) + ':' + ('0' + minutes).slice(-2);
    };

    ScheduleModal.prototype.parseWeekdayLabels = function (raw) {
        if (!raw) {
            return {};
        }

        try {
            var parsed = JSON.parse(raw);

            if (!parsed || typeof parsed !== 'object') {
                return {};
            }

            return parsed;
        } catch (error) {
            return {};
        }
    };

    ScheduleModal.prototype.setWeeklyMode = function (mode) {
        if (mode !== 'shared' && mode !== 'per_day') {
            return;
        }

        if (mode === this.state.weeklyMode) {
            return;
        }

        this.state.weeklyMode = mode;
        this.renderWeeklyMode();
    };

    ScheduleModal.prototype.getWeeklyMode = function () {
        return this.state.weeklyMode || 'shared';
    };

    ScheduleModal.prototype.renderWeeklyMode = function () {
        var mode = this.state.weeklyMode;

        this.$weeklySharedGroup.toggle(mode === 'shared');
        this.$weeklyCustomGroup.toggle(mode === 'per_day');
        this.updateWeeklyModeLabel();

        if ('shared' === mode) {
            this.renderWeeklyShared();
        } else {
            this.renderWeeklyCustom();
        }
    };

    ScheduleModal.prototype.renderWeeklyShared = function () {
        this.renderWeeklyTimesContainer(this.$weeklyTimesContainer, this.state.weeklyTimes);
    };

    ScheduleModal.prototype.renderWeeklyCustom = function () {
        if (this.state.weeklyDays.length) {
            if (this.state.weeklyActiveDay === null || this.state.weeklyDays.indexOf(this.state.weeklyActiveDay) === -1) {
                this.state.weeklyActiveDay = this.state.weeklyDays[0];
            }
        } else {
            this.state.weeklyActiveDay = null;
        }

        this.updateWeeklyCustomDisplay();
    };

    ScheduleModal.prototype.updateWeeklyModeLabel = function () {
        if (!this.$weeklyModeLabel.length) {
            return;
        }

        var labelShared = this.$weeklyModeLabel.data('label-shared') || '';
        var labelPerDay = this.$weeklyModeLabel.data('label-per-day') || '';
        var labelNone = this.$weeklyModeLabel.data('label-none') || '';
        var mode = this.state.weeklyMode;

        if (!this.state.weeklyDays.length) {
            this.$weeklyModeLabel.text(labelNone);
            return;
        }

        if ('shared' === mode) {
            this.$weeklyModeLabel.text(labelShared);
            return;
        }

        var day = this.state.weeklyActiveDay;

        if (day === null || this.state.weeklyDays.indexOf(day) === -1) {
            day = this.state.weeklyDays[0];
        }

        var label = this.weekdayLabels.hasOwnProperty(day) ? this.weekdayLabels[day] : day;
        this.$weeklyModeLabel.text(labelPerDay.replace('%s', label));
    };

    ScheduleModal.prototype.evaluateWeeklyMode = function () {
        var hasDays = this.state.weeklyDays.length > 0;
        var hasCustomTimes = false;

        if (hasDays) {
            hasCustomTimes = Object.keys(this.state.weeklyTimesByDay).some(function (dayKey) {
                return Array.isArray(this.state.weeklyTimesByDay[dayKey]) && this.state.weeklyTimesByDay[dayKey].length > 0;
            }, this);
        } else {
            this.state.weeklyTimesByDay = {};
            this.state.weeklyActiveDay = null;
        }

        var targetMode = !hasDays ? 'shared' : (hasCustomTimes ? 'per_day' : 'shared');

        if (targetMode !== this.state.weeklyMode) {
            this.state.weeklyMode = targetMode;
            this.renderWeeklyMode();
        } else {
            if ('per_day' === targetMode) {
                this.renderWeeklyCustom();
            } else {
                this.renderWeeklyShared();
            }

            this.updateWeeklyModeLabel();
        }
    };

    ScheduleModal.prototype.updateWeeklyCustomDisplay = function () {
        var day = this.state.weeklyActiveDay;

        if (day === null) {
            this.$weeklyCustomEmpty.attr('hidden', false);
            this.$weeklyCustomDisplay.attr('hidden', true);
            this.$weeklyCustomHeading.text('');
            this.$weeklyCustomTimes.empty();
            return;
        }

        if (this.state.weeklyDays.indexOf(day) === -1) {
            day = this.state.weeklyDays.length ? this.state.weeklyDays[0] : null;
            this.state.weeklyActiveDay = day;

            if (day === null) {
                this.updateWeeklyCustomDisplay();
                return;
            }
        }

        var label = this.weekdayLabels.hasOwnProperty(day) ? this.weekdayLabels[day] : day;
        var times = this.state.weeklyTimesByDay[day] || [];

        this.$weeklyCustomEmpty.attr('hidden', true);
        this.$weeklyCustomDisplay.attr('hidden', false);
        this.$weeklyCustomHeading.text(label);
        this.$weeklyCustomTimes.empty();

        if (!times.length) {
            this.$weeklyCustomTimeInput.val(this.defaults.time);
        }

        times.forEach(function (time) {
            $('<button/>', {
                type: 'button',
                class: 'button button-secondary wc-pce-time-chip',
                'data-weekly-custom-chip': true,
                'data-time': time,
                text: time + ' ×',
            }).appendTo(this.$weeklyCustomTimes);
        }, this);
    };

    ScheduleModal.prototype.renderWeeklyTimesContainer = function ($container, times) {
        $container.empty();

        if (!times || !times.length) {
            return;
        }

        times.forEach(function (time) {
            $('<button/>', {
                type: 'button',
                class: 'button button-secondary wc-pce-time-chip',
                'data-time-chip': true,
                'data-time': time,
                text: time + ' ×',
            }).appendTo($container);
        });
    };

    ScheduleModal.prototype.addWeeklyTime = function (rawValue) {
        var value = this.normalizeTime(rawValue);

        if (!value) {
            return;
        }

        if (this.state.weeklyTimes.indexOf(value) !== -1) {
            return;
        }

        this.state.weeklyTimes.push(value);
        this.state.weeklyTimes.sort();
        this.renderWeeklyShared();
        this.$weeklyTimeInput.val(this.defaults.time);
    };

    ScheduleModal.prototype.removeWeeklyTime = function (rawValue) {
        var value = this.normalizeTime(rawValue);

        if (!value) {
            return;
        }

        var index = this.state.weeklyTimes.indexOf(value);

        if (index === -1) {
            return;
        }

        this.state.weeklyTimes.splice(index, 1);
        this.renderWeeklyShared();

        if (this.state.weeklyMode === 'per_day') {
            this.removeSharedTimeFromCustom(value);
            this.updateWeeklyCustomDisplay();
        }
    };

    ScheduleModal.prototype.addWeeklyCustomTime = function (day, rawValue) {
        var value = this.normalizeTime(rawValue);

        if (!value) {
            return;
        }

        if (!Array.isArray(this.state.weeklyTimesByDay[day])) {
            this.state.weeklyTimesByDay[day] = [];
        }

        var list = this.state.weeklyTimesByDay[day];

        if (list.indexOf(value) !== -1) {
            return;
        }

        list.push(value);
        list.sort();
        this.updateWeeklyCustomDisplay();
    };

    ScheduleModal.prototype.removeWeeklyCustomTime = function (day, rawValue) {
        var value = this.normalizeTime(rawValue);

        if (!value || !Array.isArray(this.state.weeklyTimesByDay[day])) {
            return;
        }

        var list = this.state.weeklyTimesByDay[day];
        var index = list.indexOf(value);

        if (index === -1) {
            return;
        }

        list.splice(index, 1);

        if (!list.length) {
            delete this.state.weeklyTimesByDay[day];
        }

        this.updateWeeklyCustomDisplay();
    };

    ScheduleModal.prototype.removeWeeklyDay = function (day) {
        var index = this.state.weeklyDays.indexOf(day);

        if (index === -1) {
            return;
        }

        this.state.weeklyDays.splice(index, 1);
        delete this.state.weeklyTimesByDay[day];

        if (this.state.weeklyActiveDay === day) {
            this.state.weeklyActiveDay = null;
        }

        this.renderWeeklyDays();
        this.renderWeeklyCustom();
        this.evaluateWeeklyMode();
    };

    ScheduleModal.prototype.cleanupWeeklyCustomDay = function (day) {
        if (!Array.isArray(this.state.weeklyTimesByDay[day])) {
            return;
        }

        var times = this.state.weeklyTimesByDay[day].filter(function (value) {
            return !!value;
        });

        if (!times.length) {
            delete this.state.weeklyTimesByDay[day];
        } else {
            this.state.weeklyTimesByDay[day] = times;
        }
    };

    ScheduleModal.prototype.removeSharedTimeFromCustom = function (time) {
        Object.keys(this.state.weeklyTimesByDay).forEach(function (dayKey) {
            var list = this.state.weeklyTimesByDay[dayKey];

            if (!Array.isArray(list)) {
                return;
            }

            var index = list.indexOf(time);

            if (index === -1) {
                return;
            }

            list.splice(index, 1);

            if (!list.length) {
                delete this.state.weeklyTimesByDay[dayKey];
            }
        }, this);
    };

    ScheduleModal.prototype.addTime = function (type, rawValue) {
        var value = this.normalizeTime(rawValue);

        if (!value) {
            return;
        }

        var list = 'weekly' === type ? this.state.weeklyTimes : this.state.monthlyTimes;

        if (list.indexOf(value) !== -1) {
            return;
        }

        list.push(value);
        list.sort();

        this.renderTimes(type);

        if ('weekly' === type) {
            this.$weeklyTimeInput.val(this.defaults.time);
        } else {
            this.$monthlyTimeInput.val(this.defaults.time);
        }
    };

    ScheduleModal.prototype.removeTime = function (type, rawValue) {
        var value = this.normalizeTime(rawValue);

        if (!value) {
            return;
        }

        var list = 'weekly' === type ? this.state.weeklyTimes : this.state.monthlyTimes;
        var index = list.indexOf(value);

        if (index === -1) {
            return;
        }

        list.splice(index, 1);
        this.renderTimes(type);
    };

    ScheduleModal.prototype.renderTimes = function (type) {
        var list = 'weekly' === type ? this.state.weeklyTimes : this.state.monthlyTimes;
        var $container = 'weekly' === type ? this.$weeklyTimesContainer : this.$monthlyTimesContainer;

        $container.empty();

        if (!list.length) {
            return;
        }

        list.forEach(function (time) {
            var $chip = $('<button/>', {
                type: 'button',
                class: 'button button-secondary wc-pce-time-chip',
                'data-time-chip': true,
                'data-time': time,
                text: time + ' ×',
            });

            $container.append($chip);
        });
    };

    ScheduleModal.prototype.prepareSubmission = function () {
        var mode = this.getMode();
        var payload = {};
        var scheduleType = 'weekly';
        var intervalSeconds = 0;
        var enabled = 'none' === mode ? 0 : 1;

        if (this.state.actionDraft) {
            if (!this.saveActionDraft()) {
                return false;
            }
        }

        if ('none' === mode) {
            scheduleType = 'none';
        } else if ('manual' === mode) {
            scheduleType = 'cron';
            var cron = (this.$cronInput.val() || '').trim();

            if (!this.isValidCron(cron)) {
                window.alert(this.alerts.invalidCron || 'Please provide a valid cron expression.');
                return false;
            }
        } else {
            var automaticType = this.getAutomaticType();

            if ('monthly' === automaticType) {
                if (!this.state.monthlyTimes.length) {
                    window.alert(this.alerts.monthlyTimeRequired || 'Add at least one time for the monthly schedule.');
                    return false;
                }

                payload = {
                    days: [ this.state.monthlyDay ],
                    times: this.state.monthlyTimes.slice(0),
                };
                scheduleType = 'monthly';
            } else {
                if (!this.state.weeklyDays.length) {
                    window.alert(this.alerts.weekdayRequired || 'Select at least one weekday.');
                    return false;
                }

                var weeklyMode = this.getWeeklyMode();

                if ('per_day' === weeklyMode) {
                    var normalized = this.normalizeWeeklyCustomPayload();

                    if (!normalized) {
                        window.alert(this.alerts.weeklyCustomTimeRequired || 'Add at least one time slot for the selected days.');
                        return false;
                    }

                    payload = {
                        days: this.state.weeklyDays.slice(0),
                        times: normalized.sharedTimes,
                        times_by_day: normalized.timesByDay,
                        mode: 'per_day',
                    };
                } else {
                    if (!this.state.weeklyTimes.length) {
                        window.alert(this.alerts.weeklyTimeRequired || 'Add at least one time for the weekly schedule.');
                        return false;
                    }

                    payload = {
                        days: this.state.weeklyDays.slice(0),
                        times: this.state.weeklyTimes.slice(0),
                        mode: 'shared',
                    };
                }

                scheduleType = 'weekly';
            }
        }

        this.$payloadInput.val(JSON.stringify(payload));
        this.$typeInput.val(scheduleType);
        this.$intervalInput.val(intervalSeconds);
        this.$enabledInput.val(enabled);
        this.$taskIdInput.val(this.isEditing ? this.currentTaskId : '');
        this.$actionsPayloadInput.val(JSON.stringify(this.state.actions || []));

        return true;
    };

    ScheduleModal.prototype.normalizeAction = function (raw) {
        if (!raw || typeof raw !== 'object') {
            return null;
        }

        var type = typeof raw.type === 'string' ? raw.type.trim() : '';

        if (!type) {
            return null;
        }

        var config = raw.config && typeof raw.config === 'object' ? raw.config : {};

        return {
            type: type,
            config: $.extend(true, {}, config),
        };
    };

    ScheduleModal.prototype.renderActions = function () {
        var self = this;
        var actions = Array.isArray(this.state.actions) ? this.state.actions : [];

        this.$actionsContainer.empty();

        if (!actions.length) {
            this.$actionsEmptyNotice.removeAttr('hidden');
            return;
        }

        this.$actionsEmptyNotice.attr('hidden', true);

        actions.forEach(function (action, index) {
            var label = self.getActionLabel(action);
            var $item = $('<div/>', {
                class: 'wc-pce-action-item',
                'data-action-index': index,
            });

            $('<strong/>', { text: label }).appendTo($item);

            var $buttons = $('<div/>', { class: 'wc-pce-action-buttons' });

            $('<button/>', {
                type: 'button',
                class: 'button button-secondary button-small',
                'data-action-edit': true,
                text: self.strings.editAction || 'Edit',
            }).appendTo($buttons);

            $('<button/>', {
                type: 'button',
                class: 'button button-secondary button-small wc-pce-button-danger',
                'data-action-remove': true,
                text: self.strings.removeAction || 'Remove',
            }).appendTo($buttons);

            $buttons.appendTo($item);
            self.$actionsContainer.append($item);
        });
    };

    ScheduleModal.prototype.getActionLabel = function (action) {
        if (!action || !action.type) {
            return '';
        }

        var labelMap = this.actionLabels || {};
        var defaultLabel = action.type.charAt(0).toUpperCase() + action.type.slice(1);

        return labelMap[action.type] || defaultLabel;
    };

    ScheduleModal.prototype.openActionModal = function () {
        this.state.actionDraft = {
            type: 'email',
            config: {},
        };

        this.isEditingAction = false;
        this.editingActionIndex = -1;
        this.renderActionEditor();
        this.$modal.addClass('wc-pce-modal--action-editor');
    };

    ScheduleModal.prototype.closeActionModal = function (silent) {
        this.$modal.removeClass('wc-pce-modal--action-editor is-editing-action');
        this.state.actionDraft = null;
        this.isEditingAction = false;
        this.editingActionIndex = -1;

        if (!silent) {
            this.renderActionEditor();
        }
    };

    ScheduleModal.prototype.renderActionEditor = function () {
        if (!this.$actionEditor) {
            this.buildActionEditor();
        }

        var draft = this.state.actionDraft;

        if (!draft) {
            this.$actionEditor.attr('hidden', true);
            return;
        }

        this.$actionEditor.removeAttr('hidden');
        this.$actionTypeSelect.val(draft.type);
        this.renderActionConfigFields(draft.type, draft.config || {});

        var label = this.isEditingAction ? (this.strings.updateAction || 'Update action') : (this.strings.addAction || 'Add action');
        this.$actionSaveButton.text(label);
    };

    ScheduleModal.prototype.renderActionConfigFields = function (type, config) {
        var self = this;
        var definition = this.actionDefinitions ? this.actionDefinitions[type] : null;

        this.$actionConfigContainer.empty();

        if (!definition || !definition.fields) {
            return;
        }

        definition.fields.forEach(function (fieldDef) {
            var fieldId = 'wc-pce-action-field-' + fieldDef.name;
            var value = self.getActionFieldValue(config, fieldDef);
            var $row = $('<p/>', { class: 'wc-pce-action-field' }).appendTo(self.$actionConfigContainer);

            $('<label/>', {
                for: fieldId,
                text: fieldDef.label,
            }).appendTo($row);

            var $input;

            var fieldType = fieldDef.type || 'text';

            switch (fieldType) {
                case 'textarea':
                    $input = $('<textarea/>', {
                        id: fieldId,
                        rows: fieldDef.rows || 3,
                        text: value,
                    });
                    break;
                case 'json':
                    $input = $('<textarea/>', {
                        id: fieldId,
                        rows: fieldDef.rows || 3,
                        text: value,
                    });
                    break;
                case 'select':
                    $input = $('<select/>', { id: fieldId });

                    (fieldDef.options || []).forEach(function (option) {
                        $('<option/>', {
                            value: option.value,
                            text: option.label,
                            selected: option.value === value,
                        }).appendTo($input);
                    });
                    break;
                case 'checkbox':
                    $input = $('<input/>', {
                        type: 'checkbox',
                        id: fieldId,
                        checked: !!value,
                    });
                    break;
                default:
                    var attrs = {
                        type: fieldType,
                        id: fieldId,
                        value: value,
                    };

                    if (fieldDef.placeholder) {
                        attrs.placeholder = fieldDef.placeholder;
                    }

                    $input = $('<input/>', attrs);
                    break;
            }

            if (fieldDef.description) {
                $('<span/>', {
                    class: 'description',
                    text: fieldDef.description,
                }).appendTo($row);
            }

            if (fieldDef.name === 'profile_id') {
                $input.attr('type', 'number');
                $input.attr('min', '0');
            }

            $input.data('field-name', fieldDef.name);
            $input.on('change input', function () {
                self.updateActionDraftField(fieldDef, $(this));
            });

            $row.append($input);
        });
    };

    ScheduleModal.prototype.getActionFieldValue = function (config, fieldDef) {
        if (!config || !fieldDef) {
            return fieldDef.defaultValue || '';
        }

        var value = config[fieldDef.name];

        if (typeof value === 'undefined') {
            return fieldDef.defaultValue || '';
        }

        if ('checkbox' === fieldDef.type) {
            return !!value;
        }

        if ('json' === fieldDef.type) {
            if (value && typeof value === 'object') {
                try {
                    return JSON.stringify(value, null, 2);
                } catch (error) {
                    return '';
                }
            }

            return value || '';
        }

        if (fieldDef.name === 'recipients' && Array.isArray(value)) {
            return value.join(', ');
        }

        return value;
    };

    ScheduleModal.prototype.updateActionDraftField = function (fieldDef, $input) {
        if (!this.state.actionDraft) {
            return;
        }

        var value;

        if ('checkbox' === fieldDef.type) {
            value = $input.is(':checked') ? 1 : 0;
        } else if ('number' === fieldDef.type) {
            var parsed = parseInt($input.val(), 10);
            value = isNaN(parsed) ? '' : parsed;
        } else {
            value = $input.val();
        }

        this.state.actionDraft.config = this.state.actionDraft.config || {};
        this.state.actionDraft.config[fieldDef.name] = value;
    };

    ScheduleModal.prototype.saveActionDraft = function () {
        var draft = this.state.actionDraft;

        if (!draft || !draft.type) {
            return false;
        }

        var normalized = this.normalizeAction(draft);

        if (!normalized) {
            return false;
        }

        var processed = this.processActionConfig(normalized.type, normalized.config || {});

        if (processed === null) {
            return false;
        }

        if ('email' === normalized.type) {
            if (!processed.recipients || !Array.isArray(processed.recipients) || !processed.recipients.length) {
                window.alert(this.alerts.recipientRequired || 'Please enter at least one recipient email.');
                return false;
            }
        }

        normalized.config = processed;

        this.state.actions = this.state.actions || [];

        if (this.isEditingAction) {
            this.state.actions[this.editingActionIndex] = normalized;
        } else {
            this.state.actions.push(normalized);
        }

        this.state.actionDraft = null;
        this.isEditingAction = false;
        this.editingActionIndex = -1;

        this.renderActions();
        this.$actionsPayloadInput.val(JSON.stringify(this.state.actions));
        this.closeActionModal();

        return true;
    };

    ScheduleModal.prototype.editAction = function (index) {
        if (!Array.isArray(this.state.actions) || index < 0 || index >= this.state.actions.length) {
            return;
        }

        var action = this.normalizeAction(this.state.actions[index]);

        if (!action) {
            return;
        }

        this.state.actionDraft = {
            type: action.type,
            config: $.extend(true, {}, action.config || {}),
        };

        this.isEditingAction = true;
        this.editingActionIndex = index;
        this.$modal.addClass('wc-pce-modal--action-editor is-editing-action');
        this.renderActionEditor();
    };

    ScheduleModal.prototype.removeAction = function (index) {
        if (!Array.isArray(this.state.actions) || index < 0 || index >= this.state.actions.length) {
            return;
        }

        this.state.actions.splice(index, 1);
        this.renderActions();
        this.$actionsPayloadInput.val(JSON.stringify(this.state.actions));
    };

    ScheduleModal.prototype.actionOptions = (window.WCPCE_Admin && window.WCPCE_Admin.scheduleConfig && window.WCPCE_Admin.scheduleConfig.actionOptions) || [];

    ScheduleModal.prototype.processActionConfig = function (type, config) {
        var processed = $.extend(true, {}, config || {});

        switch (type) {
            case 'email':
                if (processed.recipients && 'string' === typeof processed.recipients) {
                    processed.recipients = processed.recipients
                        .split(',')
                        .map(function (item) {
                            return item.trim();
                        })
                        .filter(Boolean);
                }
                break;
            case 'webhook':
                if (processed.method && 'string' === typeof processed.method) {
                    processed.method = processed.method.toUpperCase();
                }

                if (processed.headers && 'string' === typeof processed.headers) {
                    if (!processed.headers.trim()) {
                        processed.headers = {};
                    } else {
                        try {
                            var parsed = JSON.parse(processed.headers);
                            processed.headers = parsed && typeof parsed === 'object' ? parsed : {};
                        } catch (error) {
                            window.alert(this.alerts.webhookHeadersInvalid || 'Webhook headers must be valid JSON.');
                            return null;
                        }
                    }
                }
                break;
            case 'ftp':
            case 'sftp':
                processed.port = this.toOptionalInt(processed.port);
                processed.profile_id = this.toOptionalInt(processed.profile_id);
                break;
            case 's3':
                processed.profile_id = this.toOptionalInt(processed.profile_id);
                break;
            default:
                if (processed && Object.prototype.hasOwnProperty.call(processed, 'profile_id')) {
                    processed.profile_id = this.toOptionalInt(processed.profile_id);
                }
                break;
        }

        return processed;
    };

    ScheduleModal.prototype.toOptionalInt = function (value) {
        if (value === '' || value === null || typeof value === 'undefined') {
            return '';
        }

        var parsed = parseInt(value, 10);

        return isNaN(parsed) ? '' : parsed;
    };

    ScheduleModal.prototype.isValidCron = function (expression) {
        if (!expression) {
            return false;
        }

        var parts = expression.trim().split(/\s+/);

        return parts.length >= 5 && parts.length <= 6;
    };

    ScheduleModal.prototype.parseEditData = function (raw) {
        if (!raw) {
            return null;
        }

        try {
            var data = JSON.parse(raw);

            if (!data || typeof data !== 'object') {
                return null;
            }

            return data;
        } catch (error) {
            return null;
        }
    };

    ScheduleModal.prototype.populateForm = function (data) {
        var self = this;

        this.editData = data;
        this.$taskIdInput.val(data.id || '');
        this.$nameInput.val(data.name || '');
        this.$templateSelect.val(data.template_id || '');

        var isIncremental = parseInt(data.incremental, 10) === 1;
        this.$incrementalToggle.prop('checked', isIncremental);
        this.$incrementalField.val(data.incremental_field || 'post_modified');

        var timezone = data.schedule_timezone || this.defaults.timezone;
        this.$timezone.val(timezone);

        var mode = 'automatic';
        var automaticType = 'weekly';

        if ('none' === data.schedule_type) {
            mode = 'none';
        } else if ('cron' === data.schedule_type) {
            mode = 'manual';
            this.$cronInput.val(data.schedule_cron || '');
        } else if ('monthly' === data.schedule_type) {
            automaticType = 'monthly';
        }

        this.$modeRadios.filter('[value="' + mode + '"]').prop('checked', true);
        this.$automaticTypeRadios.filter('[value="' + automaticType + '"]').prop('checked', true);

        var payload = data.schedule_payload || {};

        if ('monthly' === automaticType) {
            var monthlyDay = Array.isArray(payload.days) && payload.days.length ? parseInt(payload.days[0], 10) : NaN;

            if (isNaN(monthlyDay)) {
                this.state.monthlyDay = this.defaults.monthDay;
            } else {
                monthlyDay = Math.min(Math.max(monthlyDay, 1), 31);
                this.state.monthlyDay = monthlyDay;
            }

            var monthlyTimes = Array.isArray(payload.times) ? payload.times.map(function (time) {
                return self.normalizeTime(time);
            }).filter(function (value) {
                return !!value;
            }) : [];

            this.state.monthlyTimes = monthlyTimes.sort();
            this.state.weeklyDays = [];
            this.state.weeklyTimes = [];
            this.state.weeklyTimesByDay = {};
            this.state.weeklyMode = 'shared';
        } else {
            this.state.monthlyDay = this.defaults.monthDay;
            this.state.monthlyTimes = [];

            this.state.weeklyDays = Array.isArray(payload.days) ? payload.days.map(function (value) {
                return parseInt(value, 10);
            }).filter(function (value) {
                return !isNaN(value);
            }) : [];

            var times = Array.isArray(payload.times) ? payload.times.map(function (time) {
                return self.normalizeTime(time);
            }).filter(function (value) {
                return !!value;
            }) : [];

            var timesByDay = payload.times_by_day && typeof payload.times_by_day === 'object' ? payload.times_by_day : {};
            var hasCustom = false;

            this.state.weeklyTimesByDay = {};

            Object.keys(timesByDay).forEach(function (key) {
                var parsedDay = parseInt(key, 10);

                if (isNaN(parsedDay)) {
                    return;
                }

                var values = timesByDay[key];

                if (!Array.isArray(values) || !values.length) {
                    return;
                }

                var normalized = values.map(function (value) {
                    return self.normalizeTime(value);
                }).filter(function (value) {
                    return !!value;
                });

                if (!normalized.length) {
                    return;
                }

                hasCustom = true;
                self.state.weeklyTimesByDay[parsedDay] = normalized.sort();
            });

            if (hasCustom) {
                this.state.weeklyMode = 'per_day';
                this.state.weeklyTimes = [];
            } else {
                this.state.weeklyMode = 'shared';
                this.state.weeklyTimes = times.sort();
            }
        }

        this.$monthlyDayInput.val(this.state.monthlyDay);

        this.$enabledInput.val(parseInt(data.enabled, 10) === 0 ? 0 : 1);
        this.state.actions = Array.isArray(data.actions) ? data.actions.map(function (action) {
            return self.normalizeAction(action);
        }).filter(function (action) {
            return !!action;
        }) : [];
        this.$actionsPayloadInput.val(JSON.stringify(this.state.actions));

        this.renderWeeklyDays();
        this.renderWeeklyMode();
        this.renderTimes('monthly');
        this.renderActions();
        this.updatePanels();
        this.updateAutomaticFields();
        this.updateEnabledField();
        this.updateIncrementalVisibility();
    };

    ScheduleModal.prototype.updateModalLabels = function (mode) {
        var titleCreate = this.$title.data('title-create') || 'Scheduling options';
        var titleEdit = this.$title.data('title-edit') || titleCreate;
        var labelCreate = this.$submit.data('label-create') || this.$submit.text();
        var labelEdit = this.$submit.data('label-edit') || labelCreate;

        if ('edit' === mode) {
            this.$title.text(titleEdit);
            this.$submit.text(labelEdit);
        } else {
            this.$title.text(titleCreate);
            this.$submit.text(labelCreate);
        }
    };

    ScheduleModal.prototype.updateIncrementalVisibility = function () {
        var isChecked = this.$incrementalToggle.is(':checked');
        this.$incrementalField.closest('label').toggle(isChecked);
    };

    $(function () {
        $('.wooproduct-exporter__toggle-group').on('click', function () {
            var target = $(this).data('target');
            var section = $('.wooproduct-exporter__group[data-group="' + target + '"]');

            toggleGroup(section);
        });

        if (window.WCPCE_Admin && window.WCPCE_Admin.hasBrandTaxonomy) {
            $('[data-brand-hint]').hide();
        } else if (window.WCPCE_Admin && window.WCPCE_Admin.brandFieldHint) {
            $('[data-brand-hint]').attr('title', window.WCPCE_Admin.brandFieldHint);
        }

        $('.wooproduct-exporter__select-all').on('click', function () {
            var $btn = $(this);
            var isSelectAll = !$btn.data('selected');

            toggleAllCheckboxes(isSelectAll);
            $btn.data('selected', isSelectAll);

            if (window.WCPCE_Admin && window.WCPCE_Admin.labels) {
                $btn.text(isSelectAll ? window.WCPCE_Admin.labels.clearAll : window.WCPCE_Admin.labels.selectAll);
            }
        });

        var conditionBuilders = [];
        if (window.WCPCE_Admin && window.WCPCE_Admin.conditionBuilder) {
            $('[data-condition-builder]').each(function () {
                var $builder = $(this);
                var initialValue = {};

                try {
                    initialValue = JSON.parse($builder.find('[data-condition-builder-input]').val() || '{}');
                } catch (error) {
                    initialValue = {};
                }

                var config = $.extend(true, {}, window.WCPCE_Admin.conditionBuilder, { initial: initialValue });

                var instance = new ConditionBuilder($builder, config);
                $builder.data('conditionBuilderInstance', instance);
                conditionBuilders.push(instance);
            });
        }

        var $form = $('#wooproduct-exporter-form');
        var fieldOrdering = null;

        if ($form.length && window.WCPCE_Admin && window.WCPCE_Admin.fieldOrdering) {
            var $fieldPanel = $('[data-field-order-panel]');

            if ($fieldPanel.length) {
                fieldOrdering = new FieldOrdering({
                    form: $form,
                    panel: $fieldPanel,
                    list: $fieldPanel.find('[data-field-order-list]'),
                    input: $fieldPanel.find('[data-field-order-input]'),
                    hint: $fieldPanel.find('[data-field-order-hint]'),
                    empty: $fieldPanel.find('[data-field-order-empty]'),
                    definitions: window.WCPCE_Admin.fieldOrdering.definitions || {},
                    privateLabel: window.WCPCE_Admin.fieldOrdering.privateLabel || '',
                    strings: window.WCPCE_Admin.fieldOrdering.strings || {},
                    initial: window.WCPCE_Admin.fieldOrdering.initial || [],
                });
            }
        }

        if (window.WCPCE_Admin && $('[data-template-panel]').length) {
            new TemplateUI({
                form: $form,
                templates: window.WCPCE_Admin.templates ? window.WCPCE_Admin.templates.items || [] : [],
                selected: window.WCPCE_Admin.templates ? window.WCPCE_Admin.templates.selected || '' : '',
                strings: window.WCPCE_Admin.templateStrings || {},
                ajax: window.WCPCE_Admin.ajax || {},
                conditionBuilder: conditionBuilders[0] || null,
                fileSettings: window.WCPCE_Admin.fileSettings || {},
                fieldOrdering: fieldOrdering,
            });
        }

        if ($form.length && window.WCPCE_Admin && window.WCPCE_Admin.preview) {
            var $previewModal = $('[data-preview-modal]');

            if ($previewModal.length) {
                new PreviewModal({
                    form: $form,
                    modal: $previewModal,
                    triggers: $('[data-preview-trigger]'),
                    ajax: window.WCPCE_Admin.ajax || {},
                    config: window.WCPCE_Admin.preview || {},
                });
            }
        }

        var $scheduleModal = $('[data-schedule-modal]');

        if ($scheduleModal.length) {
            new ScheduleModal($scheduleModal);
        }
    });
})(window.jQuery);
