(function () {
	'use strict';

	if (typeof wppsDatabaseCleanup === 'undefined') {
		return;
	}

	var cfg = wppsDatabaseCleanup;
	var scanData = null;
	var busy = false;
	var activeFilter = 'all';
	var currentView = cfg.currentView || 'general';
	var confirmState = null;
	var lastCleanupError = '';
	var lastCleanupMessage = '';
	var lastCleanupReport = [];

	function $(id) {
		return document.getElementById(id);
	}

	function notice(message, type) {
		var wrap = $('wpps-dc-notices');
		if (!wrap) {
			return;
		}
		var div = document.createElement('div');
		div.className = 'notice notice-' + (type || 'info') + ' is-dismissible wpps-dc-notice';
		var p = document.createElement('p');
		p.textContent = message;
		div.appendChild(p);
		wrap.innerHTML = '';
		wrap.appendChild(div);
	}

	function formatBytes(bytes) {
		bytes = Number(bytes) || 0;
		if (bytes < 1024) {
			return bytes + ' B';
		}
		if (bytes < 1048576) {
			return (bytes / 1024).toFixed(1) + ' KB';
		}
		if (bytes < 1073741824) {
			return (bytes / 1048576).toFixed(1) + ' MB';
		}
		return (bytes / 1073741824).toFixed(2) + ' GB';
	}

	function formatNumber(n) {
		return Number(n || 0).toLocaleString();
	}

	function hasValidScan() {
		return !!(scanData && scanData.scanned_at);
	}

	function parseAjaxResponse(res) {
		return res.text().then(function (text) {
			var body = (text || '').trim();

			if ( body === '' ) {
				throw new Error(cfg.strings.errorGeneric);
			}

			if ( body.charAt(0) === '<' ) {
				throw new Error(cfg.strings.errorServerHtml || 'The server returned an unexpected response. Refresh the page or check the PHP error log.');
			}

			try {
				return JSON.parse(body);
			} catch (parseError) {
				if ( body === '0' || body === '-1' ) {
					throw new Error(cfg.strings.errorSessionExpired || 'Request failed. Refresh the page and try again.');
				}
				throw new Error(cfg.strings.errorGeneric);
			}
		});
	}

	function post(action, data) {
		var body = new FormData();
		body.append('action', action);
		Object.keys(data || {}).forEach(function (key) {
			var val = data[key];
			if (key === 'settings' && val && typeof val === 'object' && !Array.isArray(val)) {
				Object.keys(val).forEach(function (settingKey) {
					var settingVal = val[settingKey];
					if (Array.isArray(settingVal)) {
						settingVal.forEach(function (item) {
							body.append('settings[' + settingKey + '][]', item);
						});
						return;
					}
					if (typeof settingVal === 'boolean') {
						body.append('settings[' + settingKey + ']', settingVal ? '1' : '0');
						return;
					}
					body.append('settings[' + settingKey + ']', settingVal);
				});
				return;
			}
			if (Array.isArray(val)) {
				val.forEach(function (item) {
					body.append(key + '[]', item);
				});
				return;
			}
			body.append(key, val);
		});
		return fetch(cfg.ajaxUrl, {
			method: 'POST',
			credentials: 'same-origin',
			body: body
		}).then(function (res) {
			return parseAjaxResponse(res);
		});
	}

	function mergeTasks(scanTasks) {
		var merged = {};
		(cfg.taskCatalog || []).forEach(function (item) {
			merged[item.id] = {
				id: item.id,
				label: item.label,
				description: item.description,
				category: item.category,
				safe: !!item.safe,
				safety_level: item.safety_level || (item.safe ? 'safe' : 'advanced'),
				count: null,
				estimated_bytes: 0,
				scanned: false,
				cleaned: false
			};
		});
		if (scanTasks) {
			Object.keys(scanTasks).forEach(function (id) {
				if (!merged[id]) {
					merged[id] = scanTasks[id];
					merged[id].scanned = true;
					return;
				}
				merged[id].count = scanTasks[id].count;
				merged[id].estimated_bytes = scanTasks[id].estimated_bytes;
				merged[id].scanned = true;
				if (scanTasks[id].safety_level) {
					merged[id].safety_level = scanTasks[id].safety_level;
				}
				if (scanTasks[id].cleaned) {
					merged[id].cleaned = true;
				}
			});
		}
		return merged;
	}

	function safetyMeta(level) {
		if (level === 'review') {
			return { cls: 'wpps-dc-badge-review', text: cfg.strings.badgeReview || 'Review' };
		}
		if (level === 'advanced') {
			return { cls: 'wpps-dc-badge-advanced', text: cfg.strings.badgeAdvanced || 'Advanced' };
		}
		return { cls: 'wpps-dc-badge-safe', text: cfg.strings.badgeSafe || 'Safe' };
	}

	function taskMatchesFilter(task) {
		if (activeFilter === 'all') {
			return true;
		}
		if (activeFilter === 'safe') {
			return !!task.safe;
		}
		if (activeFilter === 'caution') {
			return !task.safe;
		}
		if (activeFilter === 'bloat') {
			return task.scanned && Number(task.count) > 0;
		}
		return true;
	}

	function hasSelectedTasks() {
		var checks = document.querySelectorAll('.wpps-dc-task-check:checked');
		for (var i = 0; i < checks.length; i++) {
			if (!checks[i].closest('tr').classList.contains('wpps-dc-row-hidden')) {
				return true;
			}
		}
		return false;
	}

	function hasCleanableSafeTasks() {
		return collectCleanableSafeTaskIds().length > 0;
	}

	function collectCleanableSafeTaskIds() {
		var taskIds = [];

		if (!hasValidScan()) {
			return taskIds;
		}

		(cfg.safeTaskIds || []).forEach(function (id) {
			var row = document.querySelector('#wpps-dc-results-body tr[data-task-id="' + id + '"]');
			if (!row || row.classList.contains('wpps-dc-row-hidden')) {
				return;
			}

			var check = row.querySelector('.wpps-dc-task-check:checked:not(:disabled)');
			if (check) {
				taskIds.push(id);
			}
		});

		return taskIds;
	}

	function updateActionButtons() {
		var cleanSelected = $('wpps-dc-clean-selected');
		var cleanAll = $('wpps-dc-clean-all-safe');
		var selectAll = $('wpps-dc-select-all');
		if (cleanSelected) {
			cleanSelected.disabled = busy || !hasSelectedTasks();
		}
		if (cleanAll) {
			cleanAll.disabled = busy || !hasCleanableSafeTasks();
		}
		if (selectAll) {
			selectAll.disabled = busy || !hasValidScan();
		}
	}

	function setBusy(state, text) {
		busy = state;
		var progress = $('wpps-dc-progress');
		var progressText = $('wpps-dc-progress-text');
		if (progress) {
			progress.hidden = !state || confirmModalBusy();
		}
		if (progressText && text) {
			progressText.textContent = text;
		}
		['wpps-dc-scan', 'wpps-dc-scan-hero', 'wpps-dc-clean-selected', 'wpps-dc-clean-all-safe', 'wpps-dc-save-settings'].forEach(function (id) {
			var btn = $(id);
			if (btn) {
				btn.disabled = !!state;
			}
		});
		if (!state) {
			updateActionButtons();
		}
	}

	function formatDateTime(ts) {
		if (!ts) {
			return '—';
		}
		try {
			return new Date(ts * 1000).toLocaleString();
		} catch (e) {
			return '—';
		}
	}

	function setStatText(name, text) {
		document.querySelectorAll('[data-stat="' + name + '"]').forEach(function (el) {
			var first = el.firstChild;
			if (first && first.nodeType === 3) {
				first.nodeValue = text;
			} else {
				el.insertBefore(document.createTextNode(text), el.firstChild);
			}
		});
	}

	function updateHealthStatus(data) {
		var pill = document.querySelector('[data-stat="health_status"]');
		if (!pill) {
			return;
		}

		var state = 'unknown';
		var label = cfg.strings.healthUnknown || 'Not scanned';

		if (data && data.scanned_at) {
			var overview = data.overview || {};
			var needsAttention = !!overview.revisions_warn || !!overview.autoload_warn || Number(data.issues_count || 0) > 0;
			state = needsAttention ? 'attention' : 'good';
			label = needsAttention ? (cfg.strings.healthAttention || 'Needs attention') : (cfg.strings.healthGood || 'Healthy');
		}

		pill.classList.remove('wpps-dc-health__status--good', 'wpps-dc-health__status--attention', 'wpps-dc-health__status--unknown');
		pill.classList.add('wpps-dc-health__status--' + state);
		setStatText('health_label', label);
	}

	function updateStats(data) {
		if (!data) {
			return;
		}

		var hasScan = !!data.scanned_at;

		if (data.database_bytes) {
			setStatText('database_bytes', formatBytes(data.database_bytes));
		}
		setStatText('total_bytes', hasScan ? formatBytes(data.total_bytes || 0) : '—');
		setStatText('total_count', hasScan ? formatNumber(data.total_count || 0) : '—');
		setStatText('issues_count', hasScan ? formatNumber(data.issues_count || 0) : '—');

		if (hasScan) {
			setStatText('last_scan', formatDateTime(data.scanned_at));
		}

		var summary = $('wpps-dc-scan-summary');
		if (summary && hasScan) {
			summary.textContent = (cfg.strings.scanSummary || '%1$d tasks with bloat · %2$s items · %3$s removable')
				.replace('%1$d', String(data.issues_count || 0))
				.replace('%2$s', formatNumber(data.total_count || 0))
				.replace('%3$s', formatBytes(data.total_bytes || 0));
		}

		var overview = data.overview || {};
		if (typeof overview.revisions !== 'undefined') {
			setStatText('revisions', formatNumber(overview.revisions) + ' ');
		}
		if (typeof overview.autoload_bytes !== 'undefined') {
			setStatText('autoload_bytes', formatBytes(overview.autoload_bytes) + ' ');
		}
		if (typeof overview.spam_comments !== 'undefined') {
			setStatText('spam_comments', formatNumber(overview.spam_comments));
		}

		updateHealthStatus(data);
	}

	function recomputeScanTotals() {
		if (!scanData || !scanData.tasks) {
			return;
		}
		var totalCount = 0;
		var totalBytes = 0;
		var issues = 0;
		Object.keys(scanData.tasks).forEach(function (id) {
			var task = scanData.tasks[id];
			var count = Number(task.count || 0);
			totalCount += count;
			totalBytes += Number(task.estimated_bytes || 0);
			if (count > 0) {
				issues += 1;
			}
		});
		scanData.total_count = totalCount;
		scanData.total_bytes = totalBytes;
		scanData.issues_count = issues;
	}

	function notScannedLabel(taskId) {
		if ((taskId === 'optimize_tables' || taskId === 'repair_tables') && !cfg.optimizeTables) {
			return cfg.strings.notScannedMaintenance || cfg.strings.notScanned || 'Not scanned';
		}

		return cfg.strings.notScanned || 'Not scanned';
	}

	function renderResults(data) {
		scanData = data;
		var tbody = $('wpps-dc-results-body');
		if (!tbody) {
			return;
		}

		var tasks = mergeTasks(data && data.tasks ? data.tasks : null);
		var categoryLabels = cfg.categoryLabels || {};
		tbody.innerHTML = '';

		Object.keys(tasks).forEach(function (taskId) {
			var task = tasks[taskId];
			var tr = document.createElement('tr');
			tr.dataset.taskId = taskId;
			tr.dataset.safe = task.safe ? '1' : '0';
			tr.dataset.hasBloat = task.scanned && Number(task.count) > 0 ? '1' : '0';

			if (!taskMatchesFilter(task)) {
				tr.classList.add('wpps-dc-row-hidden');
			}

			var countText = task.scanned ? formatNumber(task.count) : notScannedLabel(taskId);
			var savingsText = task.scanned ? formatBytes(task.estimated_bytes) : '—';
			var safe = !!task.safe;
			var safety = safetyMeta(task.safety_level);
			var canClean = task.scanned && Number(task.count) > 0;
			var checked = safe && canClean ? ' checked' : '';

			tr.dataset.safetyLevel = task.safety_level || (safe ? 'safe' : 'advanced');

			var statusCell;
			if (task.cleaned) {
				tr.classList.add('wpps-dc-row-cleaned');
				statusCell = '<span class="wpps-dc-badge wpps-dc-badge-cleaned"><span class="dashicons dashicons-yes" aria-hidden="true"></span>' + escapeHtml(cfg.strings.statusCleaned || 'Cleaned') + '</span>';
			} else {
				statusCell = '<span class="wpps-dc-badge ' + safety.cls + '">' + escapeHtml(safety.text) + '</span>';
				if (task.scanned && Number(task.count) === 0) {
					tr.classList.add('wpps-dc-row-empty');
				}
			}

			var actionLabel = cfg.strings.actionClean || 'Clean';

			tr.innerHTML =
				'<th scope="row" class="check-column">' +
				'<input type="checkbox" class="wpps-dc-task-check" value="' + escapeAttr(taskId) + '"' + checked + (canClean ? '' : ' disabled') + ' />' +
				'</th>' +
				'<td class="column-task column-primary" data-colname="Task">' +
				'<strong class="row-title">' + escapeHtml(task.label || taskId) + '</strong>' +
				'<span class="wpps-dc-task-desc">' + escapeHtml(task.description || '') + '</span>' +
				'</td>' +
				'<td class="column-category" data-colname="Category"><span class="wpps-dc-category">' + escapeHtml(categoryLabels[task.category] || task.category || '') + '</span></td>' +
				'<td class="column-count" data-colname="Count"><span class="wpps-dc-cell-count">' + escapeHtml(countText) + '</span></td>' +
				'<td class="column-savings" data-colname="Est. savings"><span class="wpps-dc-cell-savings">' + escapeHtml(savingsText) + '</span></td>' +
				'<td class="column-status" data-colname="Status">' + statusCell + '</td>' +
				'<td class="column-action" data-colname="Action"><button type="button" class="button button-small wpps-dc-clean-one"' + (canClean ? '' : ' disabled') + ' data-task="' + escapeAttr(taskId) + '">' + escapeHtml(actionLabel) + '</button></td>';

			tbody.appendChild(tr);
		});

		if (!tbody.children.length) {
			tbody.innerHTML = '<tr class="no-items"><td class="colspanchange" colspan="7">' + escapeHtml(cfg.strings.noneFound || 'None found') + '</td></tr>';
		}

		updateStats(data);
		updateActionButtons();
	}

	function applyFilter(filter) {
		activeFilter = filter || 'all';
		document.querySelectorAll('.wpps-dc-filter').forEach(function (btn) {
			btn.classList.toggle('is-active', btn.getAttribute('data-filter') === activeFilter);
		});

		if (!scanData) {
			renderResults(null);
			return;
		}

		document.querySelectorAll('#wpps-dc-results-body tr[data-task-id]').forEach(function (row) {
			var taskId = row.getAttribute('data-task-id');
			var tasks = mergeTasks(scanData.tasks || {});
			var task = tasks[taskId];
			row.classList.toggle('wpps-dc-row-hidden', !task || !taskMatchesFilter(task));
		});
		updateActionButtons();
	}

	function escapeHtml(text) {
		var div = document.createElement('div');
		div.textContent = text == null ? '' : String(text);
		return div.innerHTML;
	}

	function escapeAttr(text) {
		return String(text == null ? '' : text).replace(/"/g, '&quot;');
	}

	function scanStepLabel(data) {
		if (!data) {
			return cfg.strings.scanning;
		}
		var label = data.current_label || data.current || '';
		var index = Number(data.index || 0);
		var total = Number(data.total || 0);
		if (label && total > 0) {
			var text = (cfg.strings.scanningStep || 'Scanning: %s (%1$d of %2$d)')
				.replace('%s', label)
				.replace('%1$d', String(index))
				.replace('%2$d', String(total));
			if (typeof data.discovered_count !== 'undefined' && Number(data.discovered_count) > 0) {
				text += ' · ' + (cfg.strings.scanningFound || '%1$s items · %2$s found')
					.replace('%1$s', formatNumber(data.discovered_count))
					.replace('%2$s', formatBytes(data.discovered_bytes || 0));
			}
			return text;
		}
		return cfg.strings.scanning;
	}

	function abortScan() {
		return post('wpps_dc_scan_abort', { nonce: cfg.nonceScan }).catch(function () {
			return null;
		});
	}

	function runScan(force) {
		if (busy) {
			return Promise.resolve();
		}
		setBusy(true, cfg.strings.scanning);
		return post('wpps_dc_scan_init', { nonce: cfg.nonceScan, force: force ? '1' : '' })
			.then(function (json) {
				if (!json || !json.success) {
					var message = (json && json.data && json.data.message) || cfg.strings.errorGeneric;
					if (json && json.data && json.data.in_progress && !force) {
						message += ' ' + (cfg.strings.scanRestartHint || '');
					}
					throw new Error(message);
				}
				if (json.data && json.data.done && json.data.results) {
					renderResults(json.data.results);
					applyFilter(activeFilter);
					if (json.data.cached) {
						notice(cfg.strings.scanCached || cfg.strings.scanComplete, 'info');
					} else {
						notice(cfg.strings.scanComplete, 'success');
					}
					return null;
				}
				if (!json.data || !json.data.job_id) {
					throw new Error(cfg.strings.errorGeneric);
				}
				return loopScanSteps(json.data.job_id);
			})
			.then(function (results) {
				if (!results) {
					return;
				}
				renderResults(results);
				applyFilter(activeFilter);
				notice(cfg.strings.scanComplete, 'success');
			})
			.catch(function (err) {
				return abortScan().then(function () {
					notice(err.message || cfg.strings.errorGeneric, 'error');
				});
			})
			.finally(function () {
				setBusy(false);
			});
	}

	function loopScanSteps(jobId) {
		return new Promise(function (resolve, reject) {
			window.setTimeout(function () {
				post('wpps_dc_scan_step', {
					nonce: cfg.nonceScan,
					job_id: jobId
				})
					.then(function (json) {
						if (!json || !json.success) {
							reject(new Error((json && json.data && json.data.message) || cfg.strings.errorGeneric));
							return;
						}
						var fill = $('wpps-dc-progress-fill');
						if (fill && json.data && typeof json.data.progress !== 'undefined') {
							fill.style.width = Math.min(100, Number(json.data.progress) || 0) + '%';
						}
						setBusy(true, scanStepLabel(json.data));
						if (json.data && json.data.done && json.data.results) {
							resolve(json.data.results);
							return;
						}
						loopScanSteps(jobId).then(resolve).catch(reject);
					})
					.catch(function (err) {
						abortScan().finally(function () {
							reject(err);
						});
					});
			}, 40);
		});
	}

	function getTaskSelectionMeta(taskIds) {
		var catalog = {};
		(cfg.taskCatalog || []).forEach(function (item) {
			catalog[item.id] = item;
		});

		var hasCaution = false;
		taskIds.forEach(function (id) {
			var item = catalog[id] || {};
			if (item.safe === false) {
				hasCaution = true;
			}
		});

		return {
			hasCaution: hasCaution,
			showBackupWarning: !!(cfg.backupStatus && cfg.backupStatus.show_warning)
		};
	}

	function cleanupRunOptions(taskIds, overrides) {
		overrides = overrides || {};
		var meta = getTaskSelectionMeta(taskIds);
		var options = {
			backupAck: !!overrides.backupAck,
			cautionAck: !!overrides.cautionAck,
			typedConfirm: !!overrides.typedConfirm
		};

		if (options.typedConfirm) {
			if (meta.showBackupWarning || options.backupAck) {
				options.backupAck = true;
			}
			if (meta.hasCaution || options.cautionAck) {
				options.cautionAck = true;
			}
		}

		return options;
	}

	function browserActionRequiresConfirm(type, action) {
		if (['optimize', 'repair', 'convert_innodb', 'drop'].indexOf(action) !== -1) {
			return true;
		}

		if (['post_meta', 'user_meta', 'comment_meta', 'term_meta'].indexOf(type) !== -1 && action === 'delete') {
			return true;
		}

		if ((type === 'options' || type === 'transients') && ['delete', 'autoload_yes', 'autoload_no'].indexOf(action) !== -1) {
			return true;
		}

		if (type === 'cron' && action === 'delete') {
			return true;
		}

		return type === 'post_types' && action === 'delete_posts';
	}

	function selectedTaskIds() {
		var ids = [];
		document.querySelectorAll('.wpps-dc-task-check:checked').forEach(function (el) {
			var row = el.closest('tr');
			if (row && !row.classList.contains('wpps-dc-row-hidden')) {
				ids.push(el.value);
			}
		});
		return ids;
	}

	function applyCleanupResultsFromJob(job) {
		if (!job || !job.results || !scanData || !scanData.tasks) {
			return;
		}

		Object.keys(job.results).forEach(function (taskId) {
			var entry = job.results[taskId];
			var task = scanData.tasks[taskId];
			if (!task) {
				return;
			}

			var deleted = Number(entry && entry.deleted ? entry.deleted : 0);
			var currentCount = Number(task.count || 0);
			var nextCount = Math.max(0, currentCount - deleted);

			task.count = nextCount;
			task.scanned = true;
			task.estimated_bytes = nextCount === 0
				? 0
				: Math.max(0, Number(task.estimated_bytes || 0) - Number(entry.bytes || 0));

			if (deleted > 0 && nextCount === 0) {
				task.cleaned = true;
			}
		});

		recomputeScanTotals();
		renderResults(scanData);
		applyFilter(activeFilter);
	}

	function runCleanup(taskIds, options) {
		options = options || {};
		if (busy) {
			return Promise.resolve();
		}
		if (!taskIds.length) {
			notice(cfg.strings.noTasksSelected, 'warning');
			return Promise.resolve();
		}

		lastCleanupError = '';
		setBusy(true, cfg.strings.cleaning);
		markRowsState(taskIds, 'loading');

		var payload = {
			nonce: cfg.nonceClean,
			tasks: taskIds
		};

		if (options.backupAck) {
			payload.backup_ack = '1';
		}
		if (options.cautionAck) {
			payload.caution_ack = '1';
		}
		if (options.typedConfirm) {
			payload.typed_confirm = 'CLEAN';
		}
		if (options.force) {
			payload.force = '1';
		}

		return post('wpps_dc_clean_init', payload)
			.then(function (json) {
				if (!json || !json.success) {
					throw new Error((json && json.data && json.data.message) || cfg.strings.errorGeneric);
				}
				if (!json.data || !json.data.job_id) {
					throw new Error(cfg.strings.errorGeneric);
				}
				var firstStep = json.data.step;
				if (firstStep && firstStep.job) {
					reportCleanProgress(firstStep.job);
				}
				if (firstStep && firstStep.done) {
					if (!firstStep.job) {
						throw new Error(cfg.strings.errorGeneric);
					}
					return firstStep;
				}
				return loopCleanSteps(json.data.job_id);
			})
			.then(function (result) {
				if (!result) {
					return null;
				}
				if (!result.job) {
					throw new Error(cfg.strings.errorGeneric);
				}
				var deleted = result.job.totals ? result.job.totals.deleted : 0;
				var bytes = result.job.totals ? result.job.totals.bytes : 0;
				applyCleanupResultsFromJob(result.job);
				var cleanMessage = cfg.strings.cleanComplete + ' ' + cfg.strings.rowsRemoved + ': ' + formatNumber(deleted) + '. ' + cfg.strings.spaceSaved + ': ' + formatBytes(bytes) + '.';
				if (deleted === 0 && cfg.strings.cleanSafeZeroHint) {
					cleanMessage += ' ' + cfg.strings.cleanSafeZeroHint;
				}
				lastCleanupMessage = cleanMessage;
				lastCleanupReport = [];
				var jobResults = result.job.results || {};
				Object.keys(jobResults).forEach(function (key) {
					var row = jobResults[key];
					if (row && (row.deleted || 0) > 0) {
						lastCleanupReport.push({
							label: row.label || key,
							deleted: row.deleted || 0,
							bytes: row.bytes || 0
						});
					}
				});
				lastCleanupReport.sort(function (a, b) {
					return b.deleted - a.deleted;
				});
				notice(cleanMessage, deleted > 0 ? 'success' : 'info');
				var lastCleanup = document.querySelector('[data-stat="last_cleanup"]');
				if (lastCleanup) {
					lastCleanup.textContent = formatDateTime(Math.floor(Date.now() / 1000));
				}
				return result;
			})
			.catch(function (err) {
				lastCleanupError = err.message || cfg.strings.errorGeneric;
				notice(lastCleanupError, 'error');
				markRowsState(taskIds, 'error');
				return null;
			})
			.finally(function () {
				setBusy(false);
			});
	}

	function loopCleanSteps(jobId) {
		return new Promise(function (resolve, reject) {
			window.setTimeout(function () {
				post('wpps_dc_clean_step', {
					nonce: cfg.nonceClean,
					job_id: jobId
				})
					.then(function (json) {
						if (!json || !json.success) {
							reject(new Error((json && json.data && json.data.message) || cfg.strings.errorGeneric));
							return;
						}
						if (json.data && json.data.job) {
							reportCleanProgress(json.data.job);
						}
						if (json.data && json.data.done) {
							if (!json.data.job) {
								reject(new Error((json.data && json.data.message) || cfg.strings.errorGeneric));
								return;
							}
							resolve(json.data);
							return;
						}
						loopCleanSteps(jobId).then(resolve).catch(reject);
					})
					.catch(reject);
			}, 40);
		});
	}

	function collectSettingsForm() {
		var form = $('wpps-dc-settings-form');
		var settings = {
			revision_keep_count: 5,
			auto_draft_days: 1,
			trash_post_days: 30,
			trash_comment_days: 30,
			draft_post_days: 30,
			unapproved_comment_days: 30,
			excluded_post_types: [],
			optimize_tables: false,
			batch_size: 300,
			backup_warn_days: 7,
			schedule_enabled: false,
			schedule_frequency: 'weekly',
			schedule_tasks: []
		};

		if (!form) {
			return settings;
		}

		['revision_keep_count', 'auto_draft_days', 'trash_post_days', 'trash_comment_days', 'draft_post_days', 'unapproved_comment_days', 'backup_warn_days', 'batch_size'].forEach(function (name) {
			var input = form.querySelector('[name="' + name + '"]');
			if (input) {
				settings[name] = input.value;
			}
		});

		settings.optimize_tables = !!form.querySelector('[name="optimize_tables"]:checked');
		settings.schedule_enabled = !!form.querySelector('[name="schedule_enabled"]:checked');
		settings.email_report = !!form.querySelector('[name="email_report"]:checked');
		var reportEmail = form.querySelector('[name="report_email"]');
		settings.report_email = reportEmail ? reportEmail.value : '';
		var scheduleFrequency = form.querySelector('[name="schedule_frequency"]');
		if (scheduleFrequency) {
			settings.schedule_frequency = scheduleFrequency.value;
		}

		form.querySelectorAll('[name="excluded_post_types[]"]:checked').forEach(function (el) {
			settings.excluded_post_types.push(el.value);
		});
		form.querySelectorAll('[name="schedule_tasks[]"]:checked').forEach(function (el) {
			settings.schedule_tasks.push(el.value);
		});

		return settings;
	}

	function saveSettings(event) {
		event.preventDefault();
		if (busy) {
			return;
		}
		setBusy(true, cfg.strings.savingSettings || 'Saving settings…');
		post('wpps_dc_save_settings', {
			nonce: cfg.nonceSettings,
			settings: collectSettingsForm()
		})
			.then(function (json) {
				if (!json || !json.success) {
					throw new Error((json && json.data && json.data.message) || cfg.strings.errorGeneric);
				}
				if (json.data && json.data.next_run) {
					updateNextRun(json.data.next_run);
				} else {
					updateNextRun(null);
				}
				notice(cfg.strings.settingsSaved, 'success');
			})
			.catch(function (err) {
				notice(err.message || cfg.strings.errorGeneric, 'error');
			})
			.finally(function () {
				setBusy(false);
			});
	}

	function openHistoryModal(historyId) {
		var modal = $('wpps-dc-history-modal');
		var content = $('wpps-dc-history-modal-content');
		if (!modal || !content || !historyId) {
			return;
		}

		closeModals();
		content.innerHTML = '<div class="wpps-dc-loading">' + escapeHtml(cfg.strings.historyLoading || 'Loading…') + '</div>';
		modal.classList.add('is-open');
		modal.setAttribute('aria-hidden', 'false');
		syncBodyModalLock();

		post('wpps_dc_history_detail', {
			nonce: cfg.nonceHistory,
			history_id: historyId
		})
			.then(function (json) {
				if (!json || !json.success || !json.data || !json.data.html) {
					throw new Error((json && json.data && json.data.message) || cfg.strings.errorGeneric);
				}
				content.innerHTML = json.data.html;
			})
			.catch(function (err) {
				content.innerHTML = '<p>' + escapeHtml(err.message || cfg.strings.errorGeneric) + '</p>';
			});
	}

	function closeHistoryModal() {
		var modal = $('wpps-dc-history-modal');
		if (!modal) {
			return;
		}
		modal.classList.remove('is-open');
		modal.setAttribute('aria-hidden', 'true');
		syncBodyModalLock();
	}

	function bindCleanupEvents() {
		['wpps-dc-scan', 'wpps-dc-scan-hero'].forEach(function (id) {
			var btn = $(id);
			if (btn) {
				btn.addEventListener('click', function (event) {
					runScan(!!(event && event.shiftKey));
				});
			}
		});

		var cleanSelected = $('wpps-dc-clean-selected');
		if (cleanSelected) {
			cleanSelected.addEventListener('click', function (event) {
				var taskIds = selectedTaskIds();
				if (!taskIds.length) {
					notice(cfg.strings.noTasksSelected, 'warning');
					return;
				}
				var force = !!(event && event.shiftKey);
				if (force) {
					runCleanup(taskIds, cleanupRunOptions(taskIds, { typedConfirm: true, force: true }));
					return;
				}
				openCleanupConfirm(taskIds, cleanupRunOptions(taskIds, { typedConfirm: true }), cfg.strings.confirmTitleSelected);
			});
		}

		var cleanAllSafe = $('wpps-dc-clean-all-safe');
		if (cleanAllSafe) {
			cleanAllSafe.addEventListener('click', function (event) {
				var taskIds = collectCleanableSafeTaskIds();
				if (!taskIds.length) {
					notice(cfg.strings.noTasksSelected, 'warning');
					return;
				}
				var force = !!(event && event.shiftKey);
				if (force) {
					runCleanup(taskIds, cleanupRunOptions(taskIds, { typedConfirm: true, force: true }));
					return;
				}
				openCleanupConfirm(taskIds, cleanupRunOptions(taskIds, { typedConfirm: true }), cfg.strings.confirmTitleAllSafe);
			});
		}

		var selectAll = $('wpps-dc-select-all');
		if (selectAll) {
			selectAll.addEventListener('change', function () {
				document.querySelectorAll('.wpps-dc-task-check:not(:disabled)').forEach(function (el) {
					var row = el.closest('tr');
					if (row && !row.classList.contains('wpps-dc-row-hidden')) {
						el.checked = selectAll.checked;
					}
				});
				document.querySelectorAll('.wpps-dc-select-all-foot').forEach(function (el) {
					el.checked = selectAll.checked;
				});
				updateActionButtons();
			});
		}

		document.querySelectorAll('.wpps-dc-select-all-foot').forEach(function (footSelectAll) {
			footSelectAll.addEventListener('change', function () {
				var checked = footSelectAll.checked;
				if (selectAll) {
					selectAll.checked = checked;
				}
				document.querySelectorAll('.wpps-dc-select-all-foot').forEach(function (el) {
					el.checked = checked;
				});
				document.querySelectorAll('.wpps-dc-task-check:not(:disabled)').forEach(function (el) {
					var row = el.closest('tr');
					if (row && !row.classList.contains('wpps-dc-row-hidden')) {
						el.checked = checked;
					}
				});
				updateActionButtons();
			});
		});

		document.addEventListener('change', function (event) {
			if (event.target && event.target.classList && event.target.classList.contains('wpps-dc-task-check')) {
				updateActionButtons();
			}
		});

		document.addEventListener('click', function (event) {
			var target = event.target;
			if (!target || !target.classList) {
				return;
			}
			if (target.classList.contains('wpps-dc-clean-one') && !target.disabled) {
				var taskId = target.getAttribute('data-task');
				if (!taskId) {
					return;
				}
				var force = !!(event && event.shiftKey);
				if (force) {
					runCleanup([taskId], cleanupRunOptions([taskId], { typedConfirm: true, force: true }));
					return;
				}
				openCleanupConfirm([taskId], cleanupRunOptions([taskId], { typedConfirm: true }), cfg.strings.confirmTitleSingle);
			}
			if (target.classList.contains('wpps-dc-filter')) {
				applyFilter(target.getAttribute('data-filter'));
			}
		});

		if (cfg.initialScan && cfg.initialScan.scanned_at) {
			scanData = cfg.initialScan;
		}
		renderResults(scanData);
		updateActionButtons();
	}

	function bindSettingsEvents() {
		var settingsForm = $('wpps-dc-settings-form');
		if (!settingsForm) {
			return;
		}

		settingsForm.addEventListener('submit', saveSettings);

		var scheduleEnabled = $('wpps-dc-schedule-enabled');
		var scheduleBody = $('wpps-dc-schedule-body');
		var scheduleCard = settingsForm.querySelector('.wpps-dc-settings-card--schedule');

		function syncScheduleState() {
			var enabled = !!(scheduleEnabled && scheduleEnabled.checked);
			if (scheduleBody) {
				scheduleBody.classList.toggle('is-disabled', !enabled);
			}
			if (scheduleCard) {
				scheduleCard.classList.toggle('is-active', enabled);
			}
		}

		if (scheduleEnabled) {
			scheduleEnabled.addEventListener('change', syncScheduleState);
			syncScheduleState();
		}

		settingsForm.addEventListener('click', function (event) {
			var target = event.target;
			if (!target || !target.getAttribute) {
				return;
			}
			var action = target.getAttribute('data-action');
			if (!action) {
				return;
			}

			if (action === 'clear-excluded-types') {
				settingsForm.querySelectorAll('[name="excluded_post_types[]"]').forEach(function (el) {
					el.checked = false;
				});
			}

			if (action === 'clear-schedule-tasks') {
				settingsForm.querySelectorAll('[name="schedule_tasks[]"]').forEach(function (el) {
					el.checked = false;
				});
			}

			if (action === 'select-safe-tasks') {
				var safeIds = cfg.safeTaskIds || [];
				settingsForm.querySelectorAll('[name="schedule_tasks[]"]').forEach(function (el) {
					el.checked = safeIds.indexOf(el.value) !== -1;
				});
			}
		});
	}

	function updateNextRun(nextRun) {
		var nextRunEl = $('wpps-dc-next-run');
		if (!nextRunEl) {
			return;
		}
		if (!nextRun) {
			nextRunEl.hidden = true;
			return;
		}
		nextRunEl.hidden = false;
		var strong = nextRunEl.querySelector('strong');
		if (strong) {
			strong.textContent = formatDateTime(nextRun);
		}
	}

	function mountModals() {
		['wpps-dc-item-modal', 'wpps-dc-history-modal', 'wpps-dc-confirm-modal'].forEach(function (id) {
			var modal = $(id);
			if (modal && modal.parentNode !== document.body) {
				document.body.appendChild(modal);
			}
		});
	}

	function syncBodyModalLock() {
		document.body.classList.toggle('wpps-dc-modal-open', !!document.querySelector('.wpps-dc-modal-overlay.is-open'));
	}

	function closeModals() {
		closeHistoryModal();
		closeItemModal();
		closeConfirmModal();
	}

	function closeItemModal() {
		var modal = $('wpps-dc-item-modal');
		if (!modal) {
			return;
		}
		modal.classList.remove('is-open');
		modal.setAttribute('aria-hidden', 'true');
		syncBodyModalLock();
	}

	function buildCleanupSummary(taskIds) {
		var catalog = {};
		(cfg.taskCatalog || []).forEach(function (item) {
			catalog[item.id] = item;
		});
		var tasks = scanData && scanData.tasks ? scanData.tasks : {};
		var items = [];
		var totalCount = 0;
		var totalBytes = 0;
		var hasCaution = false;

		taskIds.forEach(function (id) {
			var cat = catalog[id] || {};
			var task = tasks[id] || {};
			var count = Number(task.count || 0);
			var bytes = Number(task.estimated_bytes || 0);
			totalCount += count;
			totalBytes += bytes;
			if (cat.safe === false) {
				hasCaution = true;
			}
			items.push({
				label: cat.label || id,
				count: count,
				bytes: bytes,
				level: cat.safety_level || (cat.safe ? 'safe' : 'advanced')
			});
		});

		return { items: items, totalCount: totalCount, totalBytes: totalBytes, hasCaution: hasCaution };
	}

	function setConfirmLoading(state) {
		var modal = $('wpps-dc-confirm-modal');
		var accept = $('wpps-dc-confirm-accept');
		if (!modal) {
			return;
		}
		if (accept) {
			accept.disabled = state;
			var spinner = accept.querySelector('.wpps-dc-spinner');
			if (spinner) {
				spinner.hidden = !state;
			}
		}
		modal.querySelectorAll('[data-confirm-cancel]').forEach(function (btn) {
			btn.disabled = state;
		});
		modal.classList.toggle('is-busy', state);
	}

	function confirmModalBusy() {
		var modal = $('wpps-dc-confirm-modal');
		return !!(modal && modal.classList.contains('is-open') && modal.classList.contains('is-busy'));
	}

	function showConfirmProgress(show) {
		var wrap = $('wpps-dc-confirm-progress');
		if (wrap) {
			wrap.hidden = !show;
		}
		if (show) {
			setConfirmProgress(0, cfg.strings.cleaning || 'Cleaning…');
		}
	}

	function setConfirmProgress(percent, text) {
		var fill = $('wpps-dc-confirm-progress-fill');
		if (fill) {
			fill.style.width = Math.max(0, Math.min(100, Number(percent) || 0)) + '%';
		}
		var label = $('wpps-dc-confirm-progress-text');
		if (label && typeof text !== 'undefined') {
			label.textContent = text;
		}
	}

	function reportCleanProgress(job) {
		if (!job) {
			return;
		}
		var total = (job.task_ids || []).length || 1;
		var index = Number(job.current_task_index || 0);
		var percent = Math.min(100, Math.round((index / total) * 100));

		var tableFill = $('wpps-dc-progress-fill');
		if (tableFill) {
			tableFill.style.width = percent + '%';
		}

		if (confirmModalBusy()) {
			var text = (cfg.strings.cleaningStep || 'Cleaning… (%1$d of %2$d)')
				.replace('%1$d', String(Math.min(index + 1, total)))
				.replace('%2$d', String(total));
			setConfirmProgress(percent, text);
		}
	}

	function showConfirmResult(message, report) {
		var result = $('wpps-dc-confirm-result');
		if (result) {
			result.hidden = false;
			result.innerHTML = '<span class="dashicons dashicons-yes-alt" aria-hidden="true"></span><span></span>';
			var textSpan = result.querySelector('span:last-child');
			if (textSpan) {
				textSpan.textContent = message;
			}
		}
		var breakdown = $('wpps-dc-confirm-breakdown');
		if (breakdown) {
			if (report && report.length) {
				var rows = report.map(function (item) {
					return '<li><span class="wpps-dc-confirm-breakdown__label">' + escapeHtml(item.label) +
						'</span><span class="wpps-dc-confirm-breakdown__value">' +
						escapeHtml(formatNumber(item.deleted)) + ' · ' + escapeHtml(formatBytes(item.bytes)) +
						'</span></li>';
				}).join('');
				breakdown.innerHTML = '<p class="wpps-dc-confirm-breakdown__title">' +
					escapeHtml(cfg.strings.reportBreakdown || 'What was removed') + '</p><ul>' + rows + '</ul>';
				breakdown.hidden = false;
			} else {
				breakdown.hidden = true;
				breakdown.innerHTML = '';
			}
		}
		setConfirmProgress(100);
	}

	function resetConfirmModalState() {
		var progress = $('wpps-dc-confirm-progress');
		if (progress) {
			progress.hidden = true;
		}
		setConfirmProgress(0, '');
		var result = $('wpps-dc-confirm-result');
		if (result) {
			result.hidden = true;
			result.innerHTML = '';
		}
		var breakdown = $('wpps-dc-confirm-breakdown');
		if (breakdown) {
			breakdown.hidden = true;
			breakdown.innerHTML = '';
		}
		var errorEl = $('wpps-dc-confirm-error');
		if (errorEl) {
			errorEl.hidden = true;
			errorEl.textContent = '';
		}
		var cancelBtn = $('wpps-dc-confirm-cancel');
		if (cancelBtn) {
			cancelBtn.hidden = false;
			cancelBtn.disabled = false;
		}
	}

	function closeConfirmModal(force) {
		var modal = $('wpps-dc-confirm-modal');
		if (!modal) {
			return;
		}
		if (!force && modal.classList.contains('is-busy')) {
			return;
		}
		modal.classList.remove('is-open', 'is-busy');
		modal.setAttribute('aria-hidden', 'true');
		confirmState = null;
		setConfirmLoading(false);
		resetConfirmModalState();
		syncBodyModalLock();
	}

	function openConfirm(config) {
		config = config || {};
		var modal = $('wpps-dc-confirm-modal');
		if (!modal || typeof config.run !== 'function') {
			if (typeof config.run === 'function') {
				config.run();
			}
			return;
		}

		var titleEl = $('wpps-dc-confirm-title');
		if (titleEl) {
			titleEl.textContent = config.title || cfg.strings.confirmTitleSingle || 'Confirm';
		}

		var textEl = $('wpps-dc-confirm-text');
		if (textEl) {
			textEl.textContent = config.text || cfg.strings.confirmText || '';
		}

		var summaryEl = $('wpps-dc-confirm-summary');
		if (summaryEl) {
			summaryEl.innerHTML = config.summaryHtml || '';
		}

		var acceptLabel = modal.querySelector('.wpps-dc-confirm-accept__label');
		if (acceptLabel) {
			acceptLabel.textContent = config.confirmLabel || cfg.strings.confirmTitleSingle || 'Confirm';
		}

		resetConfirmModalState();

		var backupEl = $('wpps-dc-confirm-backup');
		if (backupEl) {
			var showBackup = !!config.showBackup;
			backupEl.hidden = !showBackup && config.hideBackup === true;
			if (!backupEl.hidden) {
				var warn = !!(cfg.backupStatus && cfg.backupStatus.show_warning);
				backupEl.classList.toggle('is-warning', warn);
				var txt = backupEl.querySelector('.wpps-dc-confirm-backup__text');
				if (txt) {
					txt.textContent = warn
						? (cfg.strings.confirmBackupWarn || cfg.strings.confirmBackupHint || '')
						: (cfg.strings.confirmBackupHint || '');
				}
			}
		}

		var errorEl = $('wpps-dc-confirm-error');
		if (errorEl) {
			errorEl.hidden = true;
			errorEl.textContent = '';
		}

		confirmState = { run: config.run };
		setConfirmLoading(false);

		modal.classList.add('is-open');
		modal.setAttribute('aria-hidden', 'false');
		syncBodyModalLock();

		var accept = $('wpps-dc-confirm-accept');
		if (accept) {
			accept.focus();
		}
	}

	function openCleanupConfirm(taskIds, options, titleText) {
		if (!taskIds || !taskIds.length) {
			notice(cfg.strings.noTasksSelected, 'warning');
			return;
		}

		var summary = buildCleanupSummary(taskIds);
		var rows = summary.items.map(function (it) {
			var meta = safetyMeta(it.level);
			return '<li class="wpps-dc-confirm-item">' +
				'<span class="wpps-dc-confirm-item__name">' + escapeHtml(it.label) + '</span>' +
				'<span class="wpps-dc-confirm-item__meta">' + formatNumber(it.count) + ' · ' + formatBytes(it.bytes) + '</span>' +
				'<span class="wpps-dc-badge ' + meta.cls + '">' + escapeHtml(meta.text) + '</span>' +
				'</li>';
		}).join('');

		var summaryHtml = '<ul class="wpps-dc-confirm-list">' + rows + '</ul>' +
			'<p class="wpps-dc-confirm-total"><span>' + escapeHtml(cfg.strings.confirmTotal || 'Total') + '</span>' +
			'<strong>' + formatNumber(summary.totalCount) + ' · ' + formatBytes(summary.totalBytes) + '</strong></p>';

		openConfirm({
			title: titleText || cfg.strings.confirmTitleSingle,
			text: summary.hasCaution
				? (cfg.strings.confirmTextCaution || cfg.strings.confirmText || '')
				: (cfg.strings.confirmText || ''),
			summaryHtml: summaryHtml,
			showBackup: true,
			confirmLabel: cfg.strings.actionClean || 'Clean',
			run: function () {
				return runCleanup(taskIds, options).then(function (result) {
					return !!(result && result.job);
				});
			}
		});
	}

	function confirmAccept() {
		if (!confirmState) {
			return;
		}

		if (confirmState.completed) {
			closeConfirmModal(true);
			return;
		}

		if (typeof confirmState.run !== 'function') {
			return;
		}

		var errorEl = $('wpps-dc-confirm-error');
		if (errorEl) {
			errorEl.hidden = true;
			errorEl.textContent = '';
		}
		lastCleanupError = '';
		lastCleanupMessage = '';
		lastCleanupReport = [];
		setConfirmLoading(true);
		showConfirmProgress(true);

		Promise.resolve().then(confirmState.run).then(function (ok) {
			if (ok) {
				onConfirmSuccess();
				return;
			}
			setConfirmLoading(false);
			showConfirmProgress(false);
			if (errorEl) {
				errorEl.hidden = false;
				errorEl.textContent = lastCleanupError || cfg.strings.errorGeneric;
			}
		}).catch(function (err) {
			setConfirmLoading(false);
			showConfirmProgress(false);
			if (errorEl) {
				errorEl.hidden = false;
				errorEl.textContent = (err && err.message) || cfg.strings.errorGeneric;
			}
		});
	}

	function onConfirmSuccess() {
		setConfirmLoading(false);
		showConfirmProgress(false);
		showConfirmResult(lastCleanupMessage || cfg.strings.cleanComplete || 'Done.', lastCleanupReport);

		confirmState = { completed: true };

		var cancelBtn = $('wpps-dc-confirm-cancel');
		if (cancelBtn) {
			cancelBtn.hidden = true;
		}

		var accept = $('wpps-dc-confirm-accept');
		if (accept) {
			var label = accept.querySelector('.wpps-dc-confirm-accept__label');
			if (label) {
				label.textContent = cfg.strings.actionDone || 'Done';
			}
			accept.disabled = false;
			accept.focus();
		}
	}

	function markRowsState(taskIds, state) {
		taskIds.forEach(function (id) {
			var row = document.querySelector('#wpps-dc-results-body tr[data-task-id="' + id + '"]');
			if (!row) {
				return;
			}
			row.classList.remove('wpps-dc-row-loading', 'wpps-dc-row-error');
			var btn = row.querySelector('.wpps-dc-clean-one');
			var statusCell = row.querySelector('.column-status');

			if (state === 'loading') {
				row.classList.add('wpps-dc-row-loading');
				if (btn) {
					btn.disabled = true;
				}
				if (statusCell) {
					statusCell.innerHTML = '<span class="wpps-dc-badge wpps-dc-badge-loading"><span class="wpps-dc-spinner" aria-hidden="true"></span>' + escapeHtml(cfg.strings.statusCleaning || 'Cleaning…') + '</span>';
				}
			} else if (state === 'error') {
				row.classList.add('wpps-dc-row-error');
				if (btn) {
					btn.disabled = false;
				}
				if (statusCell) {
					statusCell.innerHTML = '<span class="wpps-dc-badge wpps-dc-badge-error">' + escapeHtml(cfg.strings.statusError || 'Failed') + '</span>';
				}
			}
		});
	}

	function renderDetailMeta(items) {
		if (!items || !items.length) {
			return '';
		}

		var html = '<dl class="wpps-dc-detail-meta">';
		items.forEach(function (item) {
			html += '<div><dt>' + escapeHtml(item.label) + '</dt><dd>' + (item.allowHtml ? item.value : escapeHtml(item.value == null ? '' : String(item.value))) + '</dd></div>';
		});
		html += '</dl>';
		return html;
	}

	function renderItemDetail(detail) {
		if (!detail || detail.error) {
			return '<p>' + escapeHtml(detail && detail.error ? detail.error : cfg.strings.errorGeneric) + '</p>';
		}

		var html = '';
		var metaItems = [];

		if (detail.ownership) {
			var own = detail.ownership;
			var ownershipValue = '<strong>' + escapeHtml(own.label || '') + '</strong>';
			if ((own.type === 'plugin' || own.type === 'theme') && own.status) {
				ownershipValue += ' <span class="wpps-dc-cell-badge is-' + ownerStatusVariant(own.status) + '">' + escapeHtml(ownerStatusLabel(own.status)) + '</span>';
			}
			if (own.confidence && !own.manual) {
				ownershipValue += ' <span class="description">(' + escapeHtml(String(own.confidence)) + '%)</span>';
			}
			ownershipValue += ' <span class="wpps-dc-owner__by wpps-dc-owner__by--' + escapeAttr(own.by || 'heuristic') + '">' + escapeHtml(ownerSourceLabel(own.by)) + '</span>';
			if (own.owners && own.owners.length > 1) {
				var extras = own.owners.slice(1).map(function (candidate) {
					return escapeHtml(candidate.label || '');
				}).filter(Boolean);
				if (extras.length) {
					ownershipValue += ' <span class="description">' + escapeHtml(cfg.strings.candidatesTitle || 'Ownership candidates') + ': ' + extras.join(', ') + '</span>';
				}
			}
			metaItems.push({
				label: cfg.strings.belongsTo || 'Belongs to',
				value: ownershipValue,
				allowHtml: true
			});
		}

		if (detail.status && detail.status.Name) {
			var status = detail.status;
			metaItems.push(
				{ label: cfg.strings.tableRows || 'Rows', value: escapeHtml(formatNumber(status.Rows || 0)) },
				{ label: cfg.strings.tableData || 'Data size', value: escapeHtml(formatBytes(status.Data_length || 0)) },
				{ label: cfg.strings.tableIndex || 'Index size', value: escapeHtml(formatBytes(status.Index_length || 0)) },
				{ label: cfg.strings.tableEngine || 'Engine', value: escapeHtml(String(status.Engine || '—')) }
			);
		}

		if (detail.size) {
			metaItems.push({ label: cfg.strings.itemSize || 'Size', value: escapeHtml(String(detail.size)) });
		}

		if (detail.autoload !== undefined && detail.autoload !== '') {
			metaItems.push({ label: cfg.strings.autoload || 'Autoload', value: escapeHtml(String(detail.autoload || '—')) });
		}

		if (detail.total !== undefined) {
			metaItems.push({ label: cfg.strings.totalPosts || 'Total posts', value: escapeHtml(formatNumber(detail.total)) });
		}

		html += renderDetailMeta(metaItems);

		if (detail.value) {
			html += '<div class="wpps-dc-value-tabs">';
			html += '<button type="button" class="button button-small is-active" data-value-tab="formatted">' + escapeHtml(cfg.strings.formattedValue || 'Formatted') + '</button>';
			html += '<button type="button" class="button button-small" data-value-tab="original">' + escapeHtml(cfg.strings.originalValue || 'Original') + '</button>';
			html += '</div>';
			html += '<pre class="wpps-dc-value-block wpps-dc-value-pane" data-value-pane="formatted">' + escapeHtml(detail.value.formatted || '') + '</pre>';
			html += '<pre class="wpps-dc-value-block wpps-dc-value-pane" data-value-pane="original" hidden>' + escapeHtml(detail.value.original || '') + '</pre>';
		}

		if (detail.columns && detail.columns.length) {
			html += '<h3>' + escapeHtml(cfg.strings.tableColumns || 'Columns') + '</h3><table class="wp-list-table widefat fixed striped"><thead><tr><th>' + escapeHtml(cfg.strings.columnField || 'Field') + '</th><th>' + escapeHtml(cfg.strings.columnType || 'Type') + '</th><th>' + escapeHtml(cfg.strings.columnNull || 'Null') + '</th><th>' + escapeHtml(cfg.strings.columnKey || 'Key') + '</th></tr></thead><tbody>';
			detail.columns.forEach(function (col) {
				html += '<tr><td>' + escapeHtml(col.Field || '') + '</td><td>' + escapeHtml(col.Type || '') + '</td><td>' + escapeHtml(col.Null || '') + '</td><td>' + escapeHtml(col.Key || '') + '</td></tr>';
			});
			html += '</tbody></table>';
		}

		if (detail.create_sql) {
			html += '<h3>' + escapeHtml(cfg.strings.createTable || 'CREATE TABLE') + '</h3><pre class="wpps-dc-value-block">' + escapeHtml(detail.create_sql) + '</pre>';
		}

		if (detail.callbacks && detail.callbacks.length) {
			html += '<h3>' + escapeHtml(cfg.strings.cronCallbacks || 'Registered callbacks') + '</h3><table class="wp-list-table widefat fixed striped"><thead><tr><th>' + escapeHtml(cfg.strings.cronCallback || 'Callback') + '</th><th>' + escapeHtml(cfg.strings.cronLocation || 'Location') + '</th></tr></thead><tbody>';
			detail.callbacks.forEach(function (cb) {
				html += '<tr><td><code>' + escapeHtml(cb.callback || '') + '</code></td><td>' + escapeHtml(cb.location || '—') + '</td></tr>';
			});
			html += '</tbody></table>';
		}

		if (detail.posts && detail.posts.length) {
			html += '<h3>' + escapeHtml(cfg.strings.recentPosts || 'Recent posts') + '</h3><table class="wp-list-table widefat fixed striped"><thead><tr><th>ID</th><th>' + escapeHtml(cfg.strings.postTitle || 'Title') + '</th><th>' + escapeHtml(cfg.strings.postStatus || 'Status') + '</th><th>' + escapeHtml(cfg.strings.postDate || 'Date') + '</th></tr></thead><tbody>';
			detail.posts.forEach(function (post) {
				html += '<tr><td>' + escapeHtml(String(post.id || '')) + '</td><td>' + escapeHtml(post.title || '') + '</td><td>' + escapeHtml(post.status || '') + '</td><td>' + escapeHtml(post.date || '') + '</td></tr>';
			});
			html += '</tbody></table>';
		}

		return html || '<p>' + escapeHtml(cfg.strings.noDetails || 'No details available.') + '</p>';
	}

	function openItemDetail(detailType, itemId, context) {
		var modal = $('wpps-dc-item-modal');
		var content = $('wpps-dc-item-modal-content');
		var titleEl = $('wpps-dc-item-modal-title');
		if (!modal || !content || !detailType || !itemId) {
			return;
		}

		closeModals();
		content.innerHTML = '<div class="wpps-dc-loading">' + escapeHtml(cfg.strings.detailLoading || 'Loading details…') + '</div>';
		if (titleEl) {
			titleEl.textContent = cfg.strings.viewItem || 'View';
		}
		modal.classList.add('is-open');
		modal.setAttribute('aria-hidden', 'false');
		syncBodyModalLock();

		var payload = {
			nonce: cfg.nonceDetail,
			detail_type: detailType,
			item_id: itemId
		};
		if (context) {
			payload.context_json = JSON.stringify(context);
		}

		post('wpps_dc_item_detail', payload)
			.then(function (json) {
				if (!json || !json.success) {
					throw new Error((json && json.data && json.data.message) || cfg.strings.errorGeneric);
				}
				content.innerHTML = renderItemDetail(json.data);
				if (titleEl && json.data && json.data.title) {
					titleEl.textContent = json.data.title;
				}
			})
			.catch(function (err) {
				content.innerHTML = '<p>' + escapeHtml(err.message || cfg.strings.errorGeneric) + '</p>';
			});
	}

	function updateOrphanSelectedCount() {
		var summary = $('wpps-dc-confirm-summary');
		if (!summary) {
			return;
		}
		var countEl = summary.querySelector('.wpps-dc-orphan-count');
		if (!countEl) {
			return;
		}
		var checked = summary.querySelectorAll('.wpps-dc-orphan-check:checked').length;
		countEl.textContent = (cfg.strings.orphanSelectedCount || '%s selected').replace('%s', formatNumber(checked));
	}

	function bindModalEvents() {
		mountModals();

		document.addEventListener('change', function (event) {
			var t = event.target;
			if (t && t.classList && t.classList.contains('wpps-dc-orphan-check')) {
				updateOrphanSelectedCount();
			}
		});

		document.addEventListener('click', function (event) {
			var target = event.target;
			if (!target || !target.closest) {
				return;
			}

			var orphanToggle = target.closest('.wpps-dc-orphan-toggle');
			if (orphanToggle) {
				event.preventDefault();
				var summaryWrap = $('wpps-dc-confirm-summary');
				if (summaryWrap) {
					var selectAll = orphanToggle.getAttribute('data-state') !== 'all';
					summaryWrap.querySelectorAll('.wpps-dc-orphan-check:not(:disabled)').forEach(function (c) {
						c.checked = selectAll;
					});
					orphanToggle.setAttribute('data-state', selectAll ? 'all' : 'none');
					orphanToggle.textContent = selectAll
						? (cfg.strings.orphanDeselectAll || 'Deselect all')
						: (cfg.strings.orphanSelectAll || 'Select all');
					updateOrphanSelectedCount();
				}
				return;
			}

			var historyBtn = target.closest('.wpps-dc-view-history');
			if (historyBtn) {
				event.preventDefault();
				openHistoryModal(historyBtn.getAttribute('data-history-id'));
				return;
			}

			var valueTab = target.closest('[data-value-tab]');
			if (valueTab) {
				var wrap = valueTab.closest('.wpps-dc-modal-content');
				if (wrap) {
					var tab = valueTab.getAttribute('data-value-tab');
					wrap.querySelectorAll('[data-value-tab]').forEach(function (btn) {
						btn.classList.toggle('is-active', btn.getAttribute('data-value-tab') === tab);
					});
					wrap.querySelectorAll('[data-value-pane]').forEach(function (pane) {
						pane.hidden = pane.getAttribute('data-value-pane') !== tab;
					});
				}
				return;
			}

			if (target.closest('#wpps-dc-confirm-accept')) {
				confirmAccept();
				return;
			}

			var confirmModal = $('wpps-dc-confirm-modal');
			if (confirmModal && confirmModal.classList.contains('is-open')) {
				if (target === confirmModal || target.closest('[data-confirm-cancel]')) {
					closeConfirmModal();
					return;
				}
			}

			var itemModal = $('wpps-dc-item-modal');
			var historyModal = $('wpps-dc-history-modal');

			if (target.closest('#wpps-dc-item-modal .wpps-dc-modal-close')) {
				closeItemModal();
				return;
			}
			if (itemModal && target === itemModal) {
				closeItemModal();
				return;
			}

			if (target.closest('#wpps-dc-history-modal .wpps-dc-modal-close')) {
				closeHistoryModal();
				return;
			}
			if (historyModal && target === historyModal) {
				closeHistoryModal();
			}
		});

		document.addEventListener('keydown', function (event) {
			if (event.key === 'Escape') {
				closeModals();
			}
		});
	}

	var browserViews = ['tables', 'options', 'post_meta', 'user_meta', 'comment_meta', 'term_meta', 'transients', 'cron', 'post_types'];

	function ownerStatusLabel(status) {
		if (status === 'active') {
			return cfg.strings.statusActive || 'Active';
		}
		if (status === 'inactive') {
			return cfg.strings.statusInactive || 'Inactive';
		}
		if (status === 'not_installed') {
			return cfg.strings.statusNotInstalled || 'Not installed';
		}
		return '';
	}

	function ownerStatusVariant(status) {
		if (status === 'active') {
			return 'ok';
		}
		if (status === 'inactive') {
			return 'warn';
		}
		if (status === 'not_installed') {
			return 'danger';
		}
		return 'neutral';
	}

	function ownerSourceLabel(by) {
		if (by === 'scan') {
			return cfg.strings.sourceScan || 'Source scan';
		}
		if (by === 'manual') {
			return cfg.strings.sourceManual || 'Manual';
		}
		return cfg.strings.sourceHeuristic || 'Name match';
	}

	function renderOwnerCell(item) {
		var owner = item.owner;
		if (!owner || typeof owner !== 'object') {
			return escapeHtml(item.belongs_to || '—');
		}

		var label = owner.label || item.belongs_to || '—';
		var html = '<span class="wpps-dc-owner is-' + escapeAttr(owner.type || 'unknown') + '">';

		html += '<span class="wpps-dc-owner__main">';
		html += '<span class="wpps-dc-owner__label">' + escapeHtml(label) + '</span>';
		if ((owner.type === 'plugin' || owner.type === 'theme') && owner.status) {
			html += '<span class="wpps-dc-cell-badge is-' + ownerStatusVariant(owner.status) + '">' + escapeHtml(ownerStatusLabel(owner.status)) + '</span>';
		}
		html += '</span>';

		var meta = '';
		if (owner.confidence && owner.by !== 'manual') {
			meta += '<span class="wpps-dc-owner__conf" title="' + escapeAttr(cfg.strings.confidenceLabel || 'Confidence') + '">' + Number(owner.confidence) + '%</span>';
		}
		meta += '<span class="wpps-dc-owner__by wpps-dc-owner__by--' + escapeAttr(owner.by || 'heuristic') + '">' + escapeHtml(ownerSourceLabel(owner.by)) + '</span>';
		if (owner.candidates && owner.candidates.length > 1) {
			meta += '<button type="button" class="button-link wpps-dc-owner-more" data-owner="' + escapeAttr(encodeURIComponent(JSON.stringify(owner))) + '">+' + (owner.candidates.length - 1) + ' ' + escapeHtml(cfg.strings.ownerMore || 'more') + '</button>';
		}
		html += '<span class="wpps-dc-owner__meta">' + meta + '</span>';

		html += '</span>';
		return html;
	}

	function openInfoModal(title, html) {
		var modal = $('wpps-dc-item-modal');
		var content = $('wpps-dc-item-modal-content');
		var titleEl = $('wpps-dc-item-modal-title');
		if (!modal || !content) {
			return;
		}
		closeModals();
		if (titleEl) {
			titleEl.textContent = title || '';
		}
		content.innerHTML = html;
		modal.classList.add('is-open');
		modal.setAttribute('aria-hidden', 'false');
		syncBodyModalLock();
	}

	function openOwnerCandidates(encoded) {
		var owner;
		try {
			owner = JSON.parse(decodeURIComponent(encoded));
		} catch (e) {
			return;
		}
		var candidates = (owner && owner.candidates) || [];
		if (!candidates.length) {
			return;
		}

		var rows = candidates.map(function (candidate) {
			var badge = candidate.status
				? '<span class="wpps-dc-cell-badge is-' + ownerStatusVariant(candidate.status) + '">' + escapeHtml(ownerStatusLabel(candidate.status)) + '</span>'
				: '';
			return '<li class="wpps-dc-candidate">' +
				'<span class="wpps-dc-candidate__label">' + escapeHtml(candidate.label || '—') + '</span> ' +
				badge +
				'</li>';
		}).join('');

		openInfoModal(cfg.strings.candidatesTitle || 'Ownership candidates', '<ul class="wpps-dc-candidate-list">' + rows + '</ul>');
	}

	document.addEventListener('click', function (event) {
		var moreBtn = event.target && event.target.closest ? event.target.closest('.wpps-dc-owner-more') : null;
		if (moreBtn) {
			event.preventDefault();
			openOwnerCandidates(moreBtn.getAttribute('data-owner'));
		}
	});

	function initBrowser(root) {
		if (!root) {
			return;
		}

		var type = root.getAttribute('data-browser-type');
		var config = (cfg.browserConfigs && cfg.browserConfigs[type]) || null;
		if (!config) {
			return;
		}

		var state = {
			page: 1,
			perPage: cfg.perPageDefault || 20,
			search: '',
			filter: 'all',
			belongsTo: 'all',
			sortBy: (config.columns && config.columns[0] && config.columns[0].key) || 'name',
			sortDir: 'DESC',
			loading: false
		};

		var tbody = root.querySelector('.wpps-dc-browser-table tbody');
		var tableWrap = root.querySelector('.wpps-dc-table-wrap');
		var loadingOverlay = root.querySelector('.wpps-dc-table-loading');
		var firstLoad = true;
		var statusEl = root.querySelector('.wpps-dc-browser-status');
		var summaryEl = root.querySelector('.wpps-dc-browser-summary');
		var selectedEl = root.querySelector('.wpps-dc-browser-selected');
		var searchInput = root.querySelector('.wpps-dc-browser-search');
		var filterSelect = root.querySelector('.wpps-dc-browser-filter[data-filter-key="filter"]') || root.querySelector('.wpps-dc-browser-filter');
		var belongsSelect = root.querySelector('.wpps-dc-browser-filter[data-filter-key="belongs_to"]');
		var prevBtn = root.querySelector('.wpps-dc-browser-prev');
		var nextBtn = root.querySelector('.wpps-dc-browser-next');
		var pageLabel = root.querySelector('.paging-input');
		var countLabel = root.querySelector('.displaying-num');
		var selectAll = root.querySelector('.wpps-dc-browser-select-all');
		var perPageSelect = root.querySelector('.wpps-dc-browser-per-page');

		if (type === 'tables' && !cfg.optimizeTables) {
			root.querySelectorAll('.wpps-dc-browser-action').forEach(function (btn) {
				var action = btn.getAttribute('data-action') || '';
				if (action === 'optimize' || action === 'repair' || action === 'convert_innodb') {
					btn.hidden = true;
				}
			});
		}

		function setStatus(message, type) {
			if (!statusEl) {
				return;
			}
			statusEl.textContent = message || '';
			statusEl.className = 'wpps-dc-browser-status' + (type ? ' is-' + type : '');
		}

		function selectedIds() {
			var ids = [];
			root.querySelectorAll('.wpps-dc-browser-check:checked').forEach(function (el) {
				ids.push(el.value);
			});
			return ids;
		}

		function updateActionButtons() {
			var selectedCount = selectedIds().length;
			var hasSelection = selectedCount > 0;
			root.querySelectorAll('.wpps-dc-browser-action').forEach(function (btn) {
				btn.disabled = state.loading || !hasSelection;
			});
			root.querySelectorAll('.wpps-dc-browser-bulk').forEach(function (btn) {
				btn.disabled = state.loading;
			});
			if (selectedEl) {
				selectedEl.hidden = !hasSelection;
				selectedEl.textContent = hasSelection
					? (cfg.strings.browserSelected || '%s selected').replace('%s', formatNumber(selectedCount))
					: '';
			}
		}

		function renderSummary(data) {
			if (!summaryEl) {
				return;
			}
			var chips = (data && data.summary) || [];
			if (!chips.length) {
				summaryEl.innerHTML = '';
				summaryEl.hidden = true;
				return;
			}
			summaryEl.hidden = false;
			summaryEl.innerHTML = chips.map(function (chip) {
				return '<span class="wpps-dc-browser-chip">' +
					'<span class="wpps-dc-browser-chip__label">' + escapeHtml(chip.label || '') + '</span>' +
					'<span class="wpps-dc-browser-chip__value">' + escapeHtml(chip.value == null ? '—' : String(chip.value)) + '</span>' +
					'</span>';
			}).join('');
		}

		var statusColumns = { core: 1, autoload: 1, expired: 1, orphan: 1, public: 1 };

		function cellHtml(column, item) {
			if (column.key === 'belongs_to') {
				return renderOwnerCell(item);
			}
			var value = item[column.key];
			var display = value == null ? '—' : String(value);
			if (column.key === 'name' && item.protected) {
				display += ' (' + (cfg.strings.protectedItem || 'Protected') + ')';
			}
			if (statusColumns[column.key]) {
				var variant = 'neutral';
				if (column.key === 'orphan') {
					variant = item.flag === 'orphan' ? 'warn' : 'ok';
				} else if (column.key === 'expired') {
					variant = item.flag === 'expired' ? 'warn' : 'ok';
				}
				return '<span class="wpps-dc-cell-badge is-' + variant + '">' + escapeHtml(display) + '</span>';
			}
			if (column.key === 'overhead' && item.recommend) {
				var recLevel = item.recommend_level === 'warn' ? 'warn' : 'info';
				return escapeHtml(display) + ' <span class="wpps-dc-cell-badge is-' + recLevel + '" title="' +
					escapeHtml(cfg.strings.recommendHint || 'Recommended maintenance') + '">' +
					escapeHtml(String(item.recommend)) + '</span>';
			}
			return escapeHtml(display);
		}

		function updateSortIndicators() {
			root.querySelectorAll('.wpps-dc-browser-table thead th').forEach(function (th) {
				var btn = th.querySelector('.wpps-dc-sort');
				if (!btn) {
					th.removeAttribute('aria-sort');
					return;
				}
				var key = btn.getAttribute('data-sort');
				btn.classList.remove('is-sorted-asc', 'is-sorted-desc');
				if (key === state.sortBy) {
					var asc = state.sortDir === 'ASC';
					btn.classList.add(asc ? 'is-sorted-asc' : 'is-sorted-desc');
					th.setAttribute('aria-sort', asc ? 'ascending' : 'descending');
				} else {
					th.setAttribute('aria-sort', 'none');
				}
			});
		}

		function renderRows(data) {
			if (!tbody) {
				return;
			}
			tbody.innerHTML = '';
			var items = (data && data.items) || [];
			var colSpan = (config.columns ? config.columns.length : 0) + 1 + (config.viewable ? 1 : 0);
			if (!items.length) {
				tbody.innerHTML = '<tr class="no-items"><td class="colspanchange" colspan="' + colSpan + '">' + escapeHtml(cfg.strings.browserEmpty || 'No items found.') + '</td></tr>';
				updateActionButtons();
				return;
			}

			items.forEach(function (item) {
				var tr = document.createElement('tr');
				var protectedRow = !!item.protected;
				if (item.flag) {
					tr.classList.add('wpps-dc-browser-row-' + item.flag);
				}
				if (protectedRow) {
					tr.classList.add('wpps-dc-browser-row-protected');
				}
				var cells = '<th scope="row" class="check-column">' +
					'<input type="checkbox" class="wpps-dc-browser-check" value="' + escapeAttr(item.id) + '"' + (protectedRow ? ' disabled' : '') + ' />' +
					'</th>';
				(config.columns || []).forEach(function (column) {
					var isPrimary = column.key === 'name' || column.key === 'meta_key' || column.key === 'hook';
					var colClass = 'column-' + column.key + (isPrimary ? ' column-primary' : '');
					var colLabel = column.label || column.key;
					cells += '<td class="' + escapeAttr(colClass) + '" data-colname="' + escapeAttr(colLabel) + '">' + cellHtml(column, item) + '</td>';
				});
				if (config.viewable) {
					cells += '<td class="column-actions"><button type="button" class="button button-small wpps-dc-view-item" data-item-id="' + escapeAttr(item.id) + '">' + escapeHtml(cfg.strings.viewItem || 'View') + '</button></td>';
				}
				tr.innerHTML = cells;
				tbody.appendChild(tr);
			});
			updateActionButtons();
		}

		function renderPagination(data) {
			var total = data ? Number(data.total || 0) : 0;
			var page = data ? Number(data.page || 1) : 1;
			var totalPages = data ? Number(data.total_pages || 1) : 1;
			if (countLabel) {
				countLabel.textContent = (cfg.strings.browserTotal || '%s items').replace('%s', formatNumber(total));
			}
			if (pageLabel) {
				pageLabel.textContent = (cfg.strings.browserPage || 'Page %1$d of %2$d')
					.replace('%1$d', String(page))
					.replace('%2$d', String(totalPages));
			}
			if (prevBtn) {
				prevBtn.disabled = page <= 1 || state.loading;
			}
			if (nextBtn) {
				nextBtn.disabled = page >= totalPages || state.loading;
			}
		}

		function renderSkeleton() {
			if (!tbody) {
				return;
			}
			var colSpan = (config.columns ? config.columns.length : 0) + 1 + (config.viewable ? 1 : 0);
			var count = Math.min(Math.max(Number(state.perPage) || 8, 4), 10);
			var rows = '';
			for (var i = 0; i < count; i++) {
				rows += '<tr class="wpps-dc-skeleton-row" aria-hidden="true"><td colspan="' + colSpan + '"><span class="wpps-dc-skeleton"></span></td></tr>';
			}
			tbody.innerHTML = rows;
		}

		function setTableLoading(on) {
			state.loading = on;
			if (tableWrap) {
				tableWrap.classList.toggle('is-loading', on);
			}
			if (loadingOverlay) {
				loadingOverlay.setAttribute('aria-hidden', on ? 'false' : 'true');
			}
		}

		function loadItems() {
			if (firstLoad) {
				renderSkeleton();
			}
			setTableLoading(true);
			setStatus('');
			if (selectAll) {
				selectAll.checked = false;
			}
			updateActionButtons();

			return post('wpps_dc_browse', {
				nonce: cfg.nonceBrowse,
				type: type,
				page: String(state.page),
				per_page: String(state.perPage),
				search: state.search,
				filter: state.filter,
				belongs_to: state.belongsTo,
				sort_by: state.sortBy,
				sort_dir: state.sortDir
			})
				.then(function (json) {
					if (!json || !json.success) {
						throw new Error((json && json.data && json.data.message) || cfg.strings.errorGeneric);
					}
					renderRows(json.data);
					renderPagination(json.data);
					renderSummary(json.data);
					updateSortIndicators();
					if (perPageSelect && json.data && json.data.per_page) {
						perPageSelect.value = String(json.data.per_page);
						state.perPage = Number(json.data.per_page) || state.perPage;
					}
					if (json.data && json.data.truncated) {
						setStatus(cfg.strings.browserTruncated || 'Showing a limited sample. Refine search or filters.', 'warning');
					} else {
						setStatus('');
					}
				})
				.catch(function (err) {
					if (tbody) {
						var colSpan = (config.columns ? config.columns.length : 0) + 1 + (config.viewable ? 1 : 0);
						tbody.innerHTML = '<tr class="no-items"><td class="colspanchange" colspan="' + colSpan + '">' + escapeHtml(err.message || cfg.strings.errorGeneric) + '</td></tr>';
					}
					setStatus(err.message || cfg.strings.errorGeneric, 'error');
				})
				.finally(function () {
					firstLoad = false;
					setTableLoading(false);
					updateActionButtons();
				});
		}

		if (searchInput) {
			var searchTimer;
			searchInput.addEventListener('input', function () {
				window.clearTimeout(searchTimer);
				searchTimer = window.setTimeout(function () {
					state.search = searchInput.value.trim();
					state.page = 1;
					loadItems();
				}, 300);
			});
		}

		function markFilterActive(select) {
			if (select) {
				select.setAttribute('data-active', (select.value && select.value !== 'all') ? '1' : '0');
			}
		}

		if (filterSelect) {
			markFilterActive(filterSelect);
			filterSelect.addEventListener('change', function () {
				state.filter = filterSelect.value || 'all';
				state.page = 1;
				markFilterActive(filterSelect);
				loadItems();
			});
		}

		if (belongsSelect) {
			markFilterActive(belongsSelect);
			belongsSelect.addEventListener('change', function () {
				state.belongsTo = belongsSelect.value || 'all';
				state.page = 1;
				markFilterActive(belongsSelect);
				loadItems();
			});
		}

		root.querySelectorAll('.wpps-dc-sort').forEach(function (btn) {
			btn.addEventListener('click', function () {
				var key = btn.getAttribute('data-sort');
				if (!key) {
					return;
				}
				if (state.sortBy === key) {
					state.sortDir = state.sortDir === 'ASC' ? 'DESC' : 'ASC';
				} else {
					state.sortBy = key;
					state.sortDir = 'DESC';
				}
				loadItems();
			});
		});

		if (prevBtn) {
			prevBtn.addEventListener('click', function () {
				if (state.page > 1) {
					state.page -= 1;
					loadItems();
				}
			});
		}

		if (nextBtn) {
			nextBtn.addEventListener('click', function () {
				state.page += 1;
				loadItems();
			});
		}

		if (perPageSelect) {
			perPageSelect.addEventListener('change', function () {
				state.perPage = Number(perPageSelect.value) || (cfg.perPageDefault || 20);
				state.page = 1;
				loadItems();
			});
		}

		var refreshBtn = root.querySelector('.wpps-dc-browser-refresh');
		if (refreshBtn) {
			refreshBtn.addEventListener('click', function () {
				loadItems();
			});
		}

		var ownerBtn = root.querySelector('.wpps-dc-owner-scan');
		var ownerStatusEl = root.querySelector('.wpps-dc-owner-scan-status');
		var ownerLabelEl = root.querySelector('.wpps-dc-owner-scan-label');
		var ownerProgress = root.querySelector('.wpps-dc-owner-progress');
		var ownerProgressFill = root.querySelector('.wpps-dc-owner-progress__fill');
		var ownerProgressMeta = root.querySelector('.wpps-dc-owner-progress__meta');
		var ownerProgressLabel = root.querySelector('.wpps-dc-owner-progress__label');
		var ownerCancelBtn = root.querySelector('.wpps-dc-owner-cancel');
		var ownerScanning = false;
		var ownerAborted = false;

		function refreshOwnerStatus() {
			var info = cfg.ownerScan || {};
			if (ownerLabelEl) {
				ownerLabelEl.textContent = info.hasData ? (cfg.strings.redetectOwners || 'Re-detect owners') : (cfg.strings.detectOwners || 'Detect owners');
			}
			if (!ownerStatusEl) {
				return;
			}
			if (info.stale) {
				ownerStatusEl.textContent = cfg.strings.ownerScanStale || '';
				ownerStatusEl.className = 'wpps-dc-owner-scan-status is-warn';
				ownerStatusEl.title = '';
			} else {
				ownerStatusEl.textContent = '';
				ownerStatusEl.className = 'wpps-dc-owner-scan-status';
				ownerStatusEl.title = info.hasData ? '' : (cfg.strings.ownerScanNever || '');
			}
		}

		function showOwnerProgress(on) {
			if (ownerProgress) {
				ownerProgress.hidden = !on;
			}
			if (on && ownerProgressFill) {
				ownerProgressFill.style.width = '0%';
			}
		}

		function setOwnerProgress(data) {
			var pct = Math.min(100, Math.round(Number(data.progress) || 0));
			if (ownerProgressFill) {
				ownerProgressFill.style.width = pct + '%';
			}
			if (ownerLabelEl) {
				ownerLabelEl.textContent = (cfg.strings.ownerScanning || 'Scanning source files… %d%%').replace('%d', String(pct));
			}
			if (ownerProgressMeta) {
				var scanned = Number(data.scanned || 0);
				var total = Number(data.total || 0);
				ownerProgressMeta.textContent = total > 0
					? (cfg.strings.ownerScanFiles || '%1$s of %2$s files')
						.replace('%1$s', formatNumber(scanned))
						.replace('%2$s', formatNumber(total))
					: '';
			}
		}

		function endOwnerScanUi() {
			ownerScanning = false;
			if (ownerBtn) {
				ownerBtn.disabled = false;
				ownerBtn.setAttribute('data-state', 'idle');
			}
			showOwnerProgress(false);
			refreshOwnerStatus();
		}

		function finishOwnerScan(data) {
			endOwnerScanUi();
			if (data && data.empty) {
				notice(cfg.strings.ownerScanEmpty || 'Nothing to scan.', 'info');
				return;
			}
			cfg.ownerScan = cfg.ownerScan || {};
			cfg.ownerScan.hasData = true;
			cfg.ownerScan.stale = false;
			cfg.ownerScan.scannedAt = Math.floor(Date.now() / 1000);
			refreshOwnerStatus();
			var summary = (data && data.summary) || {};
			notice(
				(cfg.strings.ownerScanDone || 'Owner detection complete: %1$s of %2$s items attributed.')
					.replace('%1$s', formatNumber(summary.attributed || 0))
					.replace('%2$s', formatNumber(summary.items || 0)),
				'success'
			);
			loadItems();
		}

		function ownerScanError(err) {
			if (ownerAborted) {
				return;
			}
			endOwnerScanUi();
			notice((err && err.message) || cfg.strings.ownerScanFailed || cfg.strings.errorGeneric, 'error');
		}

		function scheduleOwnerStep(jobId) {
			window.setTimeout(function () {
				if (ownerAborted) {
					return;
				}
				stepOwnerScan(jobId).catch(ownerScanError);
			}, 30);
		}

		function stepOwnerScan(jobId) {
			return post('wpps_dc_owner_scan_step', { nonce: cfg.nonceScan, job_id: jobId })
				.then(function (json) {
					if (ownerAborted) {
						return;
					}
					if (!json || !json.success) {
						throw new Error((json && json.data && json.data.message) || cfg.strings.ownerScanFailed);
					}
					var data = json.data || {};
					setOwnerProgress(data);
					if (data.done) {
						finishOwnerScan(data);
						return;
					}
					scheduleOwnerStep(jobId);
				});
		}

		if (ownerBtn) {
			ownerBtn.addEventListener('click', function () {
				if (ownerScanning) {
					return;
				}
				ownerScanning = true;
				ownerAborted = false;
				ownerBtn.disabled = true;
				ownerBtn.setAttribute('data-state', 'running');
				showOwnerProgress(true);
				if (ownerProgressLabel) {
					ownerProgressLabel.textContent = cfg.strings.ownerScanStarting || 'Preparing source scan…';
				}
				if (ownerProgressMeta) {
					ownerProgressMeta.textContent = '';
				}
				if (ownerLabelEl) {
					ownerLabelEl.textContent = cfg.strings.ownerScanStarting || 'Preparing…';
				}
				post('wpps_dc_owner_scan_init', { nonce: cfg.nonceScan })
					.then(function (json) {
						if (ownerAborted) {
							return;
						}
						if (!json || !json.success) {
							throw new Error((json && json.data && json.data.message) || cfg.strings.ownerScanFailed);
						}
						var data = json.data || {};
						if (data.done) {
							finishOwnerScan(data);
							return;
						}
						if (ownerProgressLabel) {
							ownerProgressLabel.textContent = cfg.strings.ownerScanProgress || 'Scanning source files…';
						}
						if (ownerProgressMeta && data.total_files) {
							ownerProgressMeta.textContent = (cfg.strings.ownerScanFiles || '%1$s of %2$s files')
								.replace('%1$s', formatNumber(0))
								.replace('%2$s', formatNumber(data.total_files));
						}
						scheduleOwnerStep(data.job_id);
					})
					.catch(ownerScanError);
			});
			refreshOwnerStatus();
		}

		if (ownerCancelBtn) {
			ownerCancelBtn.addEventListener('click', function () {
				if (!ownerScanning) {
					return;
				}
				ownerAborted = true;
				post('wpps_dc_owner_scan_abort', { nonce: cfg.nonceScan }).catch(function () {});
				endOwnerScanUi();
				notice(cfg.strings.ownerScanCanceled || 'Owner detection canceled.', 'info');
			});
		}

		function openOrphanConfirm(preview, actionLabel) {
			var items = (preview && preview.items) || [];
			var total = (preview && preview.total) || items.length;
			var subAction = (preview && preview.action) || 'delete';

			if (!items.length) {
				notice(cfg.strings.browserNoOrphans || 'No orphaned items found to clean.', 'info');
				return;
			}

			var rows = items.map(function (it) {
				var isProtected = !!it.protected;
				var detail = it.detail
					? '<span class="wpps-dc-orphan-item__detail">' + escapeHtml(it.detail) + '</span>'
					: '';
				var badge = isProtected
					? '<span class="wpps-dc-badge is-protected">' + escapeHtml(cfg.strings.protectedLabel || 'Protected') + '</span>'
					: '';
				return '<li class="wpps-dc-orphan-item' + (isProtected ? ' is-protected' : '') + '">' +
					'<label class="wpps-dc-orphan-item__label">' +
					'<input type="checkbox" class="wpps-dc-orphan-check" value="' + escapeHtml(it.id) + '"' +
					(isProtected ? ' disabled' : ' checked') + '>' +
					'<span class="wpps-dc-orphan-item__name">' + escapeHtml(it.label) + '</span>' +
					detail + badge +
					'</label></li>';
			}).join('');

			var moreNote = total > items.length
				? '<p class="wpps-dc-orphan-more">' + escapeHtml(
					(cfg.strings.orphanMore || 'Showing the first %1$s of %2$s items. Run the cleanup again to remove the rest.')
						.replace('%1$s', formatNumber(items.length))
						.replace('%2$s', formatNumber(total))
				) + '</p>'
				: '';

			var warnText = cfg.strings.orphanWarning ||
				'Orphaned items may still be used by code or add-ons that are temporarily inactive. Create a full backup before deleting anything.';

			var summaryHtml =
				'<div class="wpps-dc-orphan-warning"><span class="dashicons dashicons-warning" aria-hidden="true"></span>' +
				'<span>' + escapeHtml(warnText) + '</span></div>' +
				'<div class="wpps-dc-orphan-toolbar">' +
				'<span class="wpps-dc-orphan-count"></span>' +
				'<button type="button" class="wpps-dc-orphan-toggle" data-state="all">' +
				escapeHtml(cfg.strings.orphanDeselectAll || 'Deselect all') + '</button>' +
				'</div>' +
				'<ul class="wpps-dc-orphan-list">' + rows + '</ul>' + moreNote;

			openConfirm({
				title: actionLabel,
				text: cfg.strings.orphanReviewText || 'Review the items below. Only the items you keep checked will be deleted.',
				summaryHtml: summaryHtml,
				showBackup: true,
				confirmLabel: actionLabel,
				run: function () {
					var checks = document.querySelectorAll('#wpps-dc-confirm-summary .wpps-dc-orphan-check:checked');
					var ids = Array.prototype.map.call(checks, function (c) { return c.value; });
					if (!ids.length) {
						return Promise.reject(new Error(cfg.strings.orphanNoneSelected || 'Select at least one item to delete.'));
					}
					return runBrowserAction(subAction, ids, true);
				}
			});

			updateOrphanSelectedCount();
		}

		var bulkBtn = root.querySelector('.wpps-dc-browser-bulk');
		if (bulkBtn && config.bulk) {
			bulkBtn.addEventListener('click', function () {
				if (state.loading) {
					return;
				}
				var actionLabel = config.bulk.label || (cfg.strings.confirmTitleSingle || 'Confirm');
				bulkBtn.disabled = true;
				setStatus(cfg.strings.orphanLoadingPreview || 'Loading items…');
				post('wpps_dc_orphan_preview', { nonce: cfg.nonceBrowse, type: type })
					.then(function (json) {
						if (!json || !json.success) {
							throw new Error((json && json.data && json.data.message) || cfg.strings.errorGeneric);
						}
						setStatus('');
						openOrphanConfirm(json.data, actionLabel);
					})
					.catch(function (err) {
						setStatus('');
						notice((err && err.message) || cfg.strings.errorGeneric, 'error');
					})
					.finally(function () {
						bulkBtn.disabled = state.loading;
					});
			});
		}

		if (selectAll) {
			selectAll.addEventListener('change', function () {
				root.querySelectorAll('.wpps-dc-browser-check:not(:disabled)').forEach(function (el) {
					el.checked = selectAll.checked;
				});
				root.querySelectorAll('.wpps-dc-browser-select-all-foot').forEach(function (el) {
					el.checked = selectAll.checked;
				});
				updateActionButtons();
			});
		}

		root.querySelectorAll('.wpps-dc-browser-select-all-foot').forEach(function (footSelectAll) {
			footSelectAll.addEventListener('change', function () {
				var checked = footSelectAll.checked;
				if (selectAll) {
					selectAll.checked = checked;
				}
				root.querySelectorAll('.wpps-dc-browser-select-all-foot').forEach(function (el) {
					el.checked = checked;
				});
				root.querySelectorAll('.wpps-dc-browser-check:not(:disabled)').forEach(function (el) {
					el.checked = checked;
				});
				updateActionButtons();
			});
		});

		root.addEventListener('change', function (event) {
			if (event.target && event.target.classList && event.target.classList.contains('wpps-dc-browser-check')) {
				updateActionButtons();
			}
		});

		function runBrowserAction(action, ids, requiresTyped) {
			var payload = {
				nonce: cfg.nonceBrowse,
				type: type,
				browser_action: action,
				items: ids
			};
			if (requiresTyped) {
				payload.typed_confirm = 'CLEAN';
			}
			state.loading = true;
			updateActionButtons();
			return post('wpps_dc_browse_action', payload)
				.then(function (json) {
					if (!json || !json.success) {
						throw new Error((json && json.data && json.data.message) || cfg.strings.errorGeneric);
					}
					lastCleanupMessage = json.data.message || cfg.strings.cleanComplete;
					notice(lastCleanupMessage, 'success');
					return loadItems().then(function () { return true; });
				})
				.finally(function () {
					state.loading = false;
					updateActionButtons();
				});
		}

		root.querySelectorAll('.wpps-dc-browser-action').forEach(function (btn) {
			btn.addEventListener('click', function () {
				var action = btn.getAttribute('data-action');
				var confirmText = btn.getAttribute('data-confirm') || '';
				var actionLabel = btn.textContent ? btn.textContent.trim() : (cfg.strings.confirmTitleSingle || 'Confirm');
				var ids = selectedIds();
				if (!ids.length) {
					notice(cfg.strings.browserSelectItems || 'Select at least one item.', 'warning');
					return;
				}

				var requiresTyped = browserActionRequiresConfirm(type, action);

				if (!confirmText && !requiresTyped) {
					runBrowserAction(action, ids, false).catch(function (err) {
						notice(err.message || cfg.strings.errorGeneric, 'error');
					});
					return;
				}

				var countText = (cfg.strings.browserTotal || '%s items').replace('%s', formatNumber(ids.length));
				openConfirm({
					title: actionLabel,
					text: confirmText || cfg.strings.confirmText || '',
					summaryHtml: '<p class="wpps-dc-confirm-total"><span>' + escapeHtml(cfg.strings.confirmTotal || 'Total') + '</span><strong>' + escapeHtml(countText) + '</strong></p>',
					showBackup: requiresTyped,
					hideBackup: !requiresTyped,
					confirmLabel: actionLabel,
					run: function () {
						return runBrowserAction(action, ids, requiresTyped);
					}
				});
			});
		});

		root.addEventListener('click', function (event) {
			var target = event.target;
			if (!target || !target.classList) {
				return;
			}
			if (target.classList.contains('wpps-dc-view-item')) {
				event.preventDefault();
				var itemId = target.getAttribute('data-item-id');
				var detailType = config.detail_type || type;
				var context = null;
				if (detailType === 'cron') {
					try {
						context = JSON.parse(atob(itemId));
					} catch (e) {
						context = { hook: itemId };
					}
				}
				openItemDetail(detailType, itemId, context);
			}
		});

		loadItems();
	}

	bindModalEvents();

	if (currentView === 'general') {
		bindCleanupEvents();
	}
	if (currentView === 'settings') {
		bindSettingsEvents();
	}
	if (browserViews.indexOf(currentView) !== -1) {
		document.querySelectorAll('.wpps-dc-browser').forEach(initBrowser);
	}
})();
