/**
 * GoValid Forms Admin — form list & submissions list logic.
 *
 * @package GoValid_QR
 */

/* global jQuery, govalidQR */
(function ($) {
	'use strict';

	// Module-scoped storage for submissions data (used by Generate QR modal).
	var submissionsData = [];
	var submissionFieldLabels = [];

	$(document).ready(function () {
		// Detect which page we're on.
		if ($('#govalid-forms-list').length) {
			loadFormsList();
		}
		if ($('#govalid-submissions-list').length) {
			loadSubmissionsList();
		}
		if ($('#govalid-stats-dashboard').length) {
			loadStatistics();
		}
	});

	/* ------------------------------------------------------------------
	 * Statistics Dashboard
	 * ----------------------------------------------------------------*/

	// Chart color palettes.
	var chartColors = [
		'#2563eb', '#8b5cf6', '#ec4899', '#f59e0b', '#10b981',
		'#06b6d4', '#f97316', '#6366f1', '#14b8a6', '#e11d48',
		'#84cc16', '#a855f7', '#0ea5e9', '#d946ef', '#22d3ee'
	];

	var chartInstances = [];

	function loadStatistics() {
		var formId = $('#govalid-stats-dashboard').data('form-id');
		if (!formId) return;

		$.ajax({
			url: govalidQR.restUrl + 'forms/' + formId + '/statistics',
			method: 'GET',
			beforeSend: function (xhr) {
				xhr.setRequestHeader('X-WP-Nonce', govalidQR.nonce);
			},
			success: function (stats) {
				renderSummaryCards(stats.summary);
				renderTimelineChart(stats.timeline);
				renderDynamicCharts(stats);
			}
		});
	}

	function renderSummaryCards(summary) {
		$('#govalid-stat-total').text(formatNumber(summary.total));
		$('#govalid-stat-today').text(formatNumber(summary.today));
		$('#govalid-stat-week').text(formatNumber(summary.this_week));
		$('#govalid-stat-month').text(formatNumber(summary.this_month));
	}

	function renderTimelineChart(timeline) {
		var ctx = document.getElementById('govalid-chart-timeline');
		if (!ctx || typeof Chart === 'undefined') return;

		var labels = timeline.map(function (t) {
			var d = new Date(t.date);
			return d.toLocaleDateString('en', { month: 'short', day: 'numeric' });
		});
		var data = timeline.map(function (t) { return t.count; });

		var chart = new Chart(ctx, {
			type: 'line',
			data: {
				labels: labels,
				datasets: [{
					label: 'Submissions',
					data: data,
					borderColor: '#2563eb',
					backgroundColor: 'rgba(37, 99, 235, 0.08)',
					borderWidth: 2.5,
					fill: true,
					tension: 0.35,
					pointRadius: 0,
					pointHitRadius: 10,
					pointHoverRadius: 5,
					pointHoverBackgroundColor: '#2563eb'
				}]
			},
			options: {
				responsive: true,
				maintainAspectRatio: false,
				interaction: { mode: 'index', intersect: false },
				plugins: {
					legend: { display: false },
					tooltip: {
						backgroundColor: '#1e293b',
						titleFont: { size: 12 },
						bodyFont: { size: 13, weight: '600' },
						padding: 10,
						cornerRadius: 8,
						displayColors: false
					}
				},
				scales: {
					x: {
						grid: { display: false },
						ticks: { font: { size: 11 }, color: '#94a3b8', maxTicksLimit: 10 }
					},
					y: {
						beginAtZero: true,
						grid: { color: 'rgba(0,0,0,0.04)' },
						ticks: {
							font: { size: 11 },
							color: '#94a3b8',
							stepSize: 1,
							callback: function (v) { return Number.isInteger(v) ? v : ''; }
						}
					}
				}
			}
		});
		chartInstances.push(chart);
	}

	function renderDynamicCharts(stats) {
		var $grid = $('#govalid-stats-charts-grid');
		$grid.empty();

		// Field distribution charts (doughnut).
		(stats.field_stats || []).forEach(function (fs, idx) {
			var cardId = 'govalid-chart-field-' + idx;
			var html = '<div class="govalid-card">';
			html += '<h3 class="govalid-stats-chart-title">';
			html += '<span class="dashicons dashicons-chart-pie"></span>';
			html += esc(fs.field_label);
			html += '</h3>';
			html += '<div style="position:relative; height:220px;">';
			html += '<canvas id="' + cardId + '"></canvas>';
			html += '</div></div>';
			$grid.append(html);

			var labels = fs.values.map(function (v) { return v.label; });
			var data   = fs.values.map(function (v) { return v.count; });
			var colors = labels.map(function (_, i) { return chartColors[i % chartColors.length]; });

			var chart = new Chart(document.getElementById(cardId), {
				type: 'doughnut',
				data: {
					labels: labels,
					datasets: [{
						data: data,
						backgroundColor: colors,
						borderWidth: 2,
						borderColor: '#fff',
						hoverOffset: 6
					}]
				},
				options: {
					responsive: true,
					maintainAspectRatio: false,
					cutout: '60%',
					plugins: {
						legend: {
							position: 'right',
							labels: { font: { size: 12 }, padding: 12, usePointStyle: true, pointStyleWidth: 10 }
						},
						tooltip: {
							backgroundColor: '#1e293b',
							padding: 10,
							cornerRadius: 8,
							callbacks: {
								label: function (ctx) {
									var total = ctx.dataset.data.reduce(function (a, b) { return a + b; }, 0);
									var pct = total ? Math.round(ctx.raw / total * 100) : 0;
									return ctx.label + ': ' + ctx.raw + ' (' + pct + '%)';
								}
							}
						}
					}
				}
			});
			chartInstances.push(chart);
		});

		// Email domains chart (horizontal bar).
		if (stats.email_stats && stats.email_stats.length) {
			var es = stats.email_stats[0];
			var emailId = 'govalid-chart-email-domains';
			var html = '<div class="govalid-card">';
			html += '<h3 class="govalid-stats-chart-title">';
			html += '<span class="dashicons dashicons-email"></span>';
			html += 'Top Email Domains';
			html += '</h3>';
			html += '<div style="position:relative; height:220px;">';
			html += '<canvas id="' + emailId + '"></canvas>';
			html += '</div></div>';
			$grid.append(html);

			var chart = new Chart(document.getElementById(emailId), {
				type: 'bar',
				data: {
					labels: es.domains.map(function (d) { return d.label; }),
					datasets: [{
						data: es.domains.map(function (d) { return d.count; }),
						backgroundColor: '#2563eb',
						borderRadius: 6,
						barPercentage: 0.6
					}]
				},
				options: {
					responsive: true,
					maintainAspectRatio: false,
					indexAxis: 'y',
					plugins: {
						legend: { display: false },
						tooltip: { backgroundColor: '#1e293b', padding: 10, cornerRadius: 8, displayColors: false }
					},
					scales: {
						x: { beginAtZero: true, grid: { color: 'rgba(0,0,0,0.04)' }, ticks: { stepSize: 1, font: { size: 11 }, color: '#94a3b8' } },
						y: { grid: { display: false }, ticks: { font: { size: 12, weight: '500' }, color: '#475569' } }
					}
				}
			});
			chartInstances.push(chart);
		}

		// Hourly distribution (bar chart).
		if (stats.hourly && stats.hourly.length) {
			var hourlyId = 'govalid-chart-hourly';
			var html = '<div class="govalid-card">';
			html += '<h3 class="govalid-stats-chart-title">';
			html += '<span class="dashicons dashicons-clock"></span>';
			html += 'Peak Submission Hours';
			html += '</h3>';
			html += '<div style="position:relative; height:220px;">';
			html += '<canvas id="' + hourlyId + '"></canvas>';
			html += '</div></div>';
			$grid.append(html);

			var hasData = stats.hourly.some(function (h) { return h.count > 0; });
			if (hasData) {
				var maxCount = Math.max.apply(null, stats.hourly.map(function (h) { return h.count; }));
				var chart = new Chart(document.getElementById(hourlyId), {
					type: 'bar',
					data: {
						labels: stats.hourly.map(function (h) { return h.label; }),
						datasets: [{
							data: stats.hourly.map(function (h) { return h.count; }),
							backgroundColor: stats.hourly.map(function (h) {
								var intensity = maxCount > 0 ? h.count / maxCount : 0;
								return 'rgba(37, 99, 235, ' + (0.15 + intensity * 0.85) + ')';
							}),
							borderRadius: 4,
							barPercentage: 0.8
						}]
					},
					options: {
						responsive: true,
						maintainAspectRatio: false,
						plugins: {
							legend: { display: false },
							tooltip: { backgroundColor: '#1e293b', padding: 10, cornerRadius: 8, displayColors: false }
						},
						scales: {
							x: { grid: { display: false }, ticks: { font: { size: 10 }, color: '#94a3b8', maxRotation: 0 } },
							y: { beginAtZero: true, grid: { color: 'rgba(0,0,0,0.04)' }, ticks: { stepSize: 1, font: { size: 11 }, color: '#94a3b8' } }
						}
					}
				});
				chartInstances.push(chart);
			}
		}

		// Browser chart (doughnut).
		if (stats.browsers && stats.browsers.length) {
			var browserId = 'govalid-chart-browsers';
			var html = '<div class="govalid-card">';
			html += '<h3 class="govalid-stats-chart-title">';
			html += '<span class="dashicons dashicons-laptop"></span>';
			html += 'Browsers';
			html += '</h3>';
			html += '<div style="position:relative; height:220px;">';
			html += '<canvas id="' + browserId + '"></canvas>';
			html += '</div></div>';
			$grid.append(html);

			var browserColors = { 'Chrome': '#4285f4', 'Firefox': '#ff7139', 'Safari': '#007aff', 'Edge': '#0078d7', 'Opera': '#ff1b2d', 'IE': '#00adef', 'Other': '#94a3b8' };
			var bLabels = stats.browsers.map(function (b) { return b.label; });
			var bData   = stats.browsers.map(function (b) { return b.count; });
			var bColors = bLabels.map(function (l) { return browserColors[l] || '#94a3b8'; });

			var chart = new Chart(document.getElementById(browserId), {
				type: 'doughnut',
				data: {
					labels: bLabels,
					datasets: [{ data: bData, backgroundColor: bColors, borderWidth: 2, borderColor: '#fff', hoverOffset: 6 }]
				},
				options: {
					responsive: true,
					maintainAspectRatio: false,
					cutout: '60%',
					plugins: {
						legend: { position: 'right', labels: { font: { size: 12 }, padding: 12, usePointStyle: true, pointStyleWidth: 10 } },
						tooltip: {
							backgroundColor: '#1e293b', padding: 10, cornerRadius: 8,
							callbacks: {
								label: function (ctx) {
									var total = ctx.dataset.data.reduce(function (a, b) { return a + b; }, 0);
									var pct = total ? Math.round(ctx.raw / total * 100) : 0;
									return ctx.label + ': ' + ctx.raw + ' (' + pct + '%)';
								}
							}
						}
					}
				}
			});
			chartInstances.push(chart);
		}

		// Devices chart (doughnut).
		if (stats.devices && stats.devices.length) {
			var deviceId = 'govalid-chart-devices';
			var html = '<div class="govalid-card">';
			html += '<h3 class="govalid-stats-chart-title">';
			html += '<span class="dashicons dashicons-smartphone"></span>';
			html += 'Devices';
			html += '</h3>';
			html += '<div style="position:relative; height:220px;">';
			html += '<canvas id="' + deviceId + '"></canvas>';
			html += '</div></div>';
			$grid.append(html);

			var deviceColors = { 'Desktop': '#2563eb', 'Mobile': '#8b5cf6', 'Tablet': '#f59e0b' };
			var dLabels = stats.devices.map(function (d) { return d.label; });
			var dData   = stats.devices.map(function (d) { return d.count; });
			var dColors = dLabels.map(function (l) { return deviceColors[l] || '#94a3b8'; });

			var chart = new Chart(document.getElementById(deviceId), {
				type: 'doughnut',
				data: {
					labels: dLabels,
					datasets: [{ data: dData, backgroundColor: dColors, borderWidth: 2, borderColor: '#fff', hoverOffset: 6 }]
				},
				options: {
					responsive: true,
					maintainAspectRatio: false,
					cutout: '60%',
					plugins: {
						legend: { position: 'right', labels: { font: { size: 12 }, padding: 12, usePointStyle: true, pointStyleWidth: 10 } },
						tooltip: {
							backgroundColor: '#1e293b', padding: 10, cornerRadius: 8,
							callbacks: {
								label: function (ctx) {
									var total = ctx.dataset.data.reduce(function (a, b) { return a + b; }, 0);
									var pct = total ? Math.round(ctx.raw / total * 100) : 0;
									return ctx.label + ': ' + ctx.raw + ' (' + pct + '%)';
								}
							}
						}
					}
				}
			});
			chartInstances.push(chart);
		}
	}

	function formatNumber(n) {
		if (n >= 1000000) return (n / 1000000).toFixed(1) + 'M';
		if (n >= 1000) return (n / 1000).toFixed(1) + 'K';
		return n.toString();
	}

	/* ------------------------------------------------------------------
	 * Forms List
	 * ----------------------------------------------------------------*/

	function loadFormsList() {
		var $container = $('#govalid-forms-list');

		$.ajax({
			url: govalidQR.restUrl + 'forms',
			method: 'GET',
			data: { per_page: 50 },
			beforeSend: function (xhr) {
				xhr.setRequestHeader('X-WP-Nonce', govalidQR.nonce);
			},
			success: function (data) {
				var formCount = (data.items && data.items.length) ? data.items.length : 0;

				// Check form limit for free users.
				checkFormLimit(formCount);

				if (!formCount) {
					$container.html(
						'<div style="text-align:center; padding: 40px 20px; color: var(--gv-gray-400);">' +
							'<span class="dashicons dashicons-forms" style="font-size:40px; display:block; margin-bottom:10px;"></span>' +
							'<p>' + esc('No forms yet. Click "New Form" to create one.') + '</p>' +
						'</div>'
					);
					return;
				}

				var html = '<table class="wp-list-table widefat fixed striped" style="border-radius: var(--gv-radius); overflow: hidden;">';
				html += '<thead><tr>';
				html += '<th style="width:40%;">' + esc('Title') + '</th>';
				html += '<th style="width:12%;">' + esc('Status') + '</th>';
				html += '<th style="width:12%;">' + esc('Submissions') + '</th>';
				html += '<th style="width:20%;">' + esc('Shortcode') + '</th>';
				html += '<th style="width:16%;">' + esc('Actions') + '</th>';
				html += '</tr></thead><tbody>';

				data.items.forEach(function (form) {
					var statusBadge = form.status === 'published'
						? '<span class="govalid-fb-badge govalid-fb-badge--published">Published</span>'
						: '<span class="govalid-fb-badge govalid-fb-badge--draft">Draft</span>';

					var editUrl = adminUrl('admin.php?page=govalid-qr-form-builder&form_id=' + form.id);
					var subsUrl = adminUrl('admin.php?page=govalid-qr-form-submissions&form_id=' + form.id);
					var deleteUrl = adminUrl('admin-post.php?action=govalid_delete_form&form_id=' + form.id +
						'&_wpnonce=' + govalidQR.nonce);
					var qrUrl = adminUrl('admin.php?page=govalid-qr-generator&prefill_url=' +
						encodeURIComponent(getSiteUrl() + '?govalid_form=' + form.id) +
						'&prefill_name=' + encodeURIComponent(form.title));

					html += '<tr>';
					html += '<td><a href="' + editUrl + '" style="font-weight:600;">' + esc(form.title || 'Untitled') + '</a></td>';
					html += '<td>' + statusBadge + '</td>';
					html += '<td>' + parseInt(form.submission_count || 0, 10) + '</td>';
					html += '<td><code style="font-size:12px;">[govalid_form id="' + form.id + '"]</code></td>';
					html += '<td><div class="govalid-actions">';
					html += '<a href="' + editUrl + '" class="govalid-action-btn" title="Edit"><span class="dashicons dashicons-edit"></span></a>';
					html += '<a href="' + subsUrl + '" class="govalid-action-btn" title="Submissions"><span class="dashicons dashicons-list-view"></span></a>';
					html += '<a href="' + qrUrl + '" class="govalid-action-btn govalid-action-btn--primary" title="Generate QR"><span class="dashicons dashicons-screenoptions"></span></a>';
					html += '<button class="govalid-action-btn govalid-duplicate-form" data-id="' + form.id + '" title="Duplicate"><span class="dashicons dashicons-admin-page"></span></button>';
					html += '<a href="' + deleteUrl + '" class="govalid-action-btn govalid-action-btn--danger" title="Delete"' +
						' onclick="return confirm(\'Delete this form and all its submissions?\');">' +
						'<span class="dashicons dashicons-trash"></span></a>';
					html += '</div></td>';
					html += '</tr>';
				});

				html += '</tbody></table>';
				$container.html(html);

				// Duplicate form handler.
				$container.find('.govalid-duplicate-form').on('click', function (e) {
					e.preventDefault();
					var $btn = $(this);
					var formId = $btn.data('id');
					$btn.prop('disabled', true);
					$btn.find('.dashicons').removeClass('dashicons-admin-page').addClass('dashicons-update govalid-spin');

					$.ajax({
						url: govalidQR.restUrl + 'forms/' + formId + '/duplicate',
						method: 'POST',
						beforeSend: function (xhr) {
							xhr.setRequestHeader('X-WP-Nonce', govalidQR.nonce);
						},
						success: function () {
							loadFormsList();
						},
						error: function (xhr) {
							var msg = (xhr.responseJSON && xhr.responseJSON.message) || 'Failed to duplicate form.';
							alert(msg);
							$btn.prop('disabled', false);
							$btn.find('.dashicons').removeClass('dashicons-update govalid-spin').addClass('dashicons-admin-page');
						}
					});
				});
			},
			error: function () {
				$container.html('<div class="notice notice-error"><p>Failed to load forms.</p></div>');
			}
		});
	}

	/* ------------------------------------------------------------------
	 * Form Limit Check
	 * ----------------------------------------------------------------*/

	/**
	 * Check subscription and enforce form creation limit.
	 * Free users: max 1 form. Paid/institution: unlimited.
	 */
	function checkFormLimit(formCount) {
		if (formCount < 1) return; // No forms yet, nothing to limit.

		$.ajax({
			url: govalidQR.restUrl + 'subscription',
			method: 'GET',
			beforeSend: function (xhr) {
				xhr.setRequestHeader('X-WP-Nonce', govalidQR.nonce);
			},
			success: function (resp) {
				var d = resp.data || resp;
				var sub = d.subscription || {};
				var plan = sub.plan || {};
				var tier = (plan.tier || 'FREE').toUpperCase();

				if (tier === 'FREE' && formCount >= 1) {
					disableFormCreation();
				}
			},
			error: function () {
				// If we can't fetch subscription, assume free — enforce limit.
				if (formCount >= 1) {
					disableFormCreation();
				}
			}
		});
	}

	function disableFormCreation() {
		// Show upgrade banner.
		$('#govalid-form-limit-banner').show();

		// Disable "New Form" button.
		var $btn = $('#govalid-new-form-btn');
		$btn.removeAttr('href')
			.css({ opacity: 0.5, cursor: 'not-allowed', 'pointer-events': 'none' })
			.attr('title', 'Upgrade your plan to create more forms');

		// Disable duplicate buttons.
		$('.govalid-duplicate-form').each(function () {
			$(this).prop('disabled', true)
				.css({ opacity: 0.4, cursor: 'not-allowed' })
				.attr('title', 'Upgrade your plan to duplicate forms')
				.off('click')
				.on('click', function (e) { e.preventDefault(); });
		});
	}

	/* ------------------------------------------------------------------
	 * Submissions List
	 * ----------------------------------------------------------------*/

	function loadSubmissionsList() {
		var $container = $('#govalid-submissions-list');
		var formId = $container.data('form-id');
		if (!formId) return;

		$.ajax({
			url: govalidQR.restUrl + 'forms/' + formId + '/submissions',
			method: 'GET',
			data: { per_page: 50 },
			beforeSend: function (xhr) {
				xhr.setRequestHeader('X-WP-Nonce', govalidQR.nonce);
			},
			success: function (data) {
				if (!data.items || !data.items.length) {
					$container.html(
						'<div style="text-align:center; padding: 40px 20px; color: var(--gv-gray-400);">' +
							'<span class="dashicons dashicons-format-aside" style="font-size:40px; display:block; margin-bottom:10px;"></span>' +
							'<p>No submissions yet.</p>' +
						'</div>'
					);
					return;
				}

				// Store data in module scope for the Generate QR modal.
				submissionsData = data.items;

				// Collect all unique field labels from the first submission.
				var fieldLabels = [];
				if (data.items[0].values) {
					data.items[0].values.forEach(function (v) {
						if (fieldLabels.indexOf(v.field_label) === -1) {
							fieldLabels.push(v.field_label);
						}
					});
				}
				submissionFieldLabels = fieldLabels;

				var html = '<div style="overflow-x:auto; -webkit-overflow-scrolling:touch; border-radius: var(--gv-radius);">';
				html += '<table class="wp-list-table widefat striped" style="border-radius: var(--gv-radius); overflow: hidden; min-width:' + Math.max(700, 200 + fieldLabels.length * 160) + 'px;">';
				html += '<thead><tr>';
				html += '<th style="width:36px; padding:8px 4px; text-align:center;"><input type="checkbox" id="govalid-sub-select-all" title="Select all" /></th>';
				html += '<th style="width:40px;">#</th>';
				html += '<th style="width:140px; white-space:nowrap;">Date</th>';
				fieldLabels.forEach(function (label) {
					html += '<th style="min-width:120px; white-space:nowrap;">' + esc(label) + '</th>';
				});
				html += '<th style="width:120px; white-space:nowrap;">Actions</th>';
				html += '</tr></thead><tbody>';

				data.items.forEach(function (sub) {
					html += '<tr>';
					html += '<td style="padding:8px 4px; text-align:center;"><input type="checkbox" class="govalid-sub-checkbox" value="' + sub.id + '" /></td>';
					html += '<td>' + sub.id + '</td>';
					html += '<td>' + esc(sub.created_at) + '</td>';

					fieldLabels.forEach(function (label) {
						var val = '';
						(sub.values || []).forEach(function (v) {
							if (v.field_label === label) val = v.field_value;
						});
						html += '<td>' + renderFieldValue(val) + '</td>';
					});

					html += '<td><div class="govalid-actions">';
					html += '<button class="govalid-action-btn govalid-view-submission" data-id="' + sub.id + '" title="View"><span class="dashicons dashicons-visibility"></span></button>';
					html += '<button class="govalid-action-btn govalid-action-btn--danger govalid-delete-submission" data-id="' + sub.id + '" title="Delete"><span class="dashicons dashicons-trash"></span></button>';
					html += '</div></td>';
					html += '</tr>';
				});

				html += '</tbody></table>';
				html += '</div>'; // end scroll wrapper

				// Bulk action bar (hidden by default).
				html += '<div id="govalid-sub-bulk-bar" style="display:none;">';
				html += '<span class="dashicons dashicons-screenoptions" style="font-size:18px; color:var(--gv-primary);"></span>';
				html += '<span style="font-size:13px; color:var(--gv-gray-700);"><strong class="govalid-sub-bulk-count">0</strong> submission(s) selected</span>';
				html += '<button type="button" class="button button-primary" id="govalid-sub-generate-qr" style="margin-left:auto;">';
				html += '<span class="dashicons dashicons-screenoptions" style="margin-top:4px;"></span> Generate QR';
				html += '</button>';
				html += '</div>';

				$container.html(html);

				// Bind view/delete handlers.
				$container.on('click', '.govalid-view-submission', function () {
					viewSubmission($(this).data('id'));
				});
				$container.on('click', '.govalid-delete-submission', function () {
					var $btn = $(this);
					if (!confirm('Delete this submission?')) return;
					deleteSubmission($btn.data('id'), function () {
						$btn.closest('tr').fadeOut(function () { $(this).remove(); });
					});
				});

				// Select All checkbox.
				$container.on('change', '#govalid-sub-select-all', function () {
					var checked = $(this).is(':checked');
					$('.govalid-sub-checkbox').prop('checked', checked);
					updateSubBulkBar();
				});

				// Individual checkbox.
				$container.on('change', '.govalid-sub-checkbox', function () {
					var total = $('.govalid-sub-checkbox').length;
					var checked = $('.govalid-sub-checkbox:checked').length;
					$('#govalid-sub-select-all').prop('checked', total > 0 && checked === total);
					updateSubBulkBar();
				});

				// Generate QR button.
				$container.on('click', '#govalid-sub-generate-qr', function () {
					openGenerateQRModal();
				});
			},
			error: function () {
				$container.html('<div class="notice notice-error"><p>Failed to load submissions.</p></div>');
			}
		});
	}

	/**
	 * Update the bulk action bar visibility and count.
	 */
	function updateSubBulkBar() {
		var count = $('.govalid-sub-checkbox:checked').length;
		if (count > 0) {
			$('#govalid-sub-bulk-bar').css('display', 'flex').find('.govalid-sub-bulk-count').text(count);
		} else {
			$('#govalid-sub-bulk-bar').hide();
		}
	}

	/* ------------------------------------------------------------------
	 * Generate Custom QR Modal
	 * ----------------------------------------------------------------*/

	function openGenerateQRModal() {
		var $checked = $('.govalid-sub-checkbox:checked');
		var count = $checked.length;
		if (!count) return;

		// Collect selected submission IDs.
		var selectedIds = [];
		$checked.each(function () {
			selectedIds.push(parseInt($(this).val(), 10));
		});

		// Build field checklist from stored field labels.
		var fieldsHtml = '';
		submissionFieldLabels.forEach(function (label) {
			fieldsHtml += '<label style="display:flex; align-items:center; gap:8px; padding:6px 0; cursor:pointer;">';
			fieldsHtml += '<input type="checkbox" class="govalid-qr-field-check" value="' + esc(label) + '" checked />';
			fieldsHtml += '<span style="font-size:14px; color:var(--gv-gray-700);">' + esc(label) + '</span>';
			fieldsHtml += '</label>';
		});

		var html = '<div class="govalid-modal-overlay" id="govalid-generate-qr-modal">';
		html += '<div class="govalid-modal-content" style="max-width:540px; max-height:80vh; overflow-y:auto;">';
		html += '<button class="govalid-modal-close">&times;</button>';

		// Header.
		html += '<h3 style="margin:0 0 4px; font-size:18px;"><span class="dashicons dashicons-screenoptions" style="margin-right:6px;"></span>Generate Custom QR Codes</h3>';
		html += '<p style="font-size:13px; color:var(--gv-gray-500); margin:0 0 20px;">' + count + ' submission(s) selected. One QR code will be generated per submission.</p>';

		// QR Name.
		html += '<div style="margin-bottom:16px;">';
		html += '<label style="display:block; font-size:12px; font-weight:600; color:var(--gv-gray-600); margin-bottom:4px;">QR Code Name</label>';
		html += '<input type="text" id="govalid-custom-qr-name" value="Form Submission" class="govalid-modal-input" />';
		html += '</div>';

		// Security Level — use <div> instead of <label> to avoid native radio toggle conflicts.
		html += '<div style="margin-bottom:16px;">';
		html += '<label style="display:block; font-size:12px; font-weight:600; color:var(--gv-gray-600); margin-bottom:8px;">Security Level</label>';
		html += '<div style="display:flex; gap:8px;">';
		html += '<div class="govalid-modal-security-card active" data-level="SMART">';
		html += '<span class="dashicons dashicons-shield"></span>';
		html += '<strong>Smart</strong>';
		html += '</div>';
		html += '<div class="govalid-modal-security-card" data-level="SECURE">';
		html += '<span class="dashicons dashicons-lock"></span>';
		html += '<strong>Secure</strong>';
		html += '</div>';
		html += '<div class="govalid-modal-security-card" data-level="ENTERPRISE">';
		html += '<span class="dashicons dashicons-shield-alt"></span>';
		html += '<strong>Enterprise</strong>';
		html += '</div>';
		html += '</div>';
		html += '</div>';

		// Password Protection.
		html += '<div style="margin-bottom:16px;">';
		html += '<div style="display:flex; align-items:center; gap:10px; padding:10px 14px; border:1px solid var(--gv-gray-200); border-radius:8px; cursor:pointer;" id="govalid-pw-toggle-row">';
		html += '<label style="position:relative; display:inline-block; width:36px; height:20px; margin:0; cursor:pointer;">';
		html += '<input type="checkbox" id="govalid-pw-toggle" style="opacity:0; width:0; height:0;" />';
		html += '<span style="position:absolute; inset:0; background:var(--gv-gray-300); border-radius:20px; transition:background .2s;"></span>';
		html += '<span style="position:absolute; top:2px; left:2px; width:16px; height:16px; background:#fff; border-radius:50%; transition:transform .2s; box-shadow:0 1px 3px rgba(0,0,0,.2);" id="govalid-pw-slider"></span>';
		html += '</label>';
		html += '<span style="font-size:13px; font-weight:600; color:var(--gv-gray-700);"><span class="dashicons dashicons-lock" style="font-size:16px; width:16px; height:16px; margin-right:4px; vertical-align:text-bottom;"></span>Password Protection</span>';
		html += '</div>';

		// Password options body (hidden by default).
		html += '<div id="govalid-pw-body" style="display:none; margin-top:10px; padding:12px 14px; border:1px solid var(--gv-gray-200); border-radius:8px; background:var(--gv-gray-50);">';

		// Radio: master vs unique.
		html += '<div style="display:flex; flex-direction:column; gap:10px; margin-bottom:12px;">';
		html += '<label style="display:flex; align-items:center; gap:8px; cursor:pointer; font-size:13px; color:var(--gv-gray-700);">';
		html += '<input type="radio" name="govalid_pw_type" value="master" checked style="accent-color:var(--gv-primary);" />';
		html += 'Use QR-master password <span style="font-size:11px; color:var(--gv-gray-400);">(from account settings)</span>';
		html += '</label>';
		html += '<label style="display:flex; align-items:center; gap:8px; cursor:pointer; font-size:13px; color:var(--gv-gray-700);">';
		html += '<input type="radio" name="govalid_pw_type" value="unique" style="accent-color:var(--gv-primary);" />';
		html += 'Set QR-unique password';
		html += '</label>';
		html += '</div>';

		// Unique password inputs (hidden by default).
		html += '<div id="govalid-pw-unique-container" style="display:none;">';

		// Password input.
		html += '<div style="position:relative; margin-bottom:4px;">';
		html += '<div style="display:flex; align-items:center; border:1px solid var(--gv-gray-300); border-radius:8px; background:#fff; overflow:hidden;">';
		html += '<span style="flex-shrink:0; width:36px; display:flex; align-items:center; justify-content:center; color:var(--gv-gray-400);"><span class="dashicons dashicons-lock"></span></span>';
		html += '<input type="password" id="govalid-pw-input" placeholder="Enter password (min 6 characters)" style="flex:1; border:none; padding:8px 36px 8px 0; font-size:13px; outline:none; background:transparent;" />';
		html += '<button type="button" class="govalid-pw-vis-toggle" style="position:absolute; right:4px; top:50%; transform:translateY(-50%); background:none; border:none; cursor:pointer; color:var(--gv-gray-400); padding:4px;"><span class="dashicons dashicons-visibility"></span></button>';
		html += '</div>';
		// Strength bar.
		html += '<div style="height:4px; background:transparent; border-radius:4px; margin:4px 0 0; overflow:hidden;">';
		html += '<div id="govalid-pw-strength-bar" style="height:100%; width:0; border-radius:4px; transition:width .3s ease, background .3s ease;"></div>';
		html += '</div>';
		html += '</div>';

		// Confirm password input.
		html += '<div style="position:relative; margin-top:8px;">';
		html += '<div style="display:flex; align-items:center; border:1px solid var(--gv-gray-300); border-radius:8px; background:#fff; overflow:hidden;">';
		html += '<span style="flex-shrink:0; width:36px; display:flex; align-items:center; justify-content:center; color:var(--gv-gray-400);"><span class="dashicons dashicons-shield"></span></span>';
		html += '<input type="password" id="govalid-pw-confirm" placeholder="Confirm password" style="flex:1; border:none; padding:8px 36px 8px 0; font-size:13px; outline:none; background:transparent;" />';
		html += '<button type="button" class="govalid-pw-vis-toggle" style="position:absolute; right:4px; top:50%; transform:translateY(-50%); background:none; border:none; cursor:pointer; color:var(--gv-gray-400); padding:4px;"><span class="dashicons dashicons-visibility"></span></button>';
		html += '</div>';
		html += '</div>';

		html += '</div>'; // end unique container
		html += '</div>'; // end pw body
		html += '</div>'; // end pw section

		// Fields Checklist.
		html += '<div style="margin-bottom:20px;">';
		html += '<label style="display:block; font-size:12px; font-weight:600; color:var(--gv-gray-600); margin-bottom:8px;">Include Fields in QR Data</label>';
		html += '<div style="border:1px solid var(--gv-gray-200); border-radius:8px; padding:8px 12px; max-height:200px; overflow-y:auto;">';
		html += fieldsHtml;
		html += '</div>';
		html += '<div style="margin-top:6px; display:flex; gap:8px;">';
		html += '<a href="#" id="govalid-fields-select-all" style="font-size:12px;">Select all</a>';
		html += '<a href="#" id="govalid-fields-deselect-all" style="font-size:12px;">Deselect all</a>';
		html += '</div>';
		html += '</div>';

		// Buttons.
		html += '<div style="display:flex; gap:8px; justify-content:flex-end;">';
		html += '<button type="button" class="button govalid-modal-cancel">Cancel</button>';
		html += '<button type="button" class="button button-primary" id="govalid-confirm-generate-qr">';
		html += '<span class="dashicons dashicons-screenoptions" style="margin-top:4px;"></span> Generate ' + count + ' QR Code' + (count > 1 ? 's' : '');
		html += '</button>';
		html += '</div>';

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

		$('body').append(html);

		// Security level card click.
		$('#govalid-generate-qr-modal .govalid-modal-security-card').on('click', function () {
			$('#govalid-generate-qr-modal .govalid-modal-security-card').removeClass('active');
			$(this).addClass('active');
		});

		// Password protection toggle.
		$('#govalid-pw-toggle-row').on('click', function (e) {
			if ($(e.target).closest('.govalid-pw-vis-toggle').length) return;
			var $cb = $('#govalid-pw-toggle');
			// Toggle checkbox if click wasn't directly on it.
			if (!$(e.target).is($cb)) {
				$cb.prop('checked', !$cb.prop('checked'));
			}
			var isOn = $cb.prop('checked');
			var $slider = $('#govalid-pw-slider');
			$slider.prev('span').css('background', isOn ? 'var(--gv-primary)' : 'var(--gv-gray-300)');
			$slider.css('transform', isOn ? 'translateX(16px)' : 'translateX(0)');
			if (isOn) {
				$('#govalid-pw-body').slideDown(200);
			} else {
				$('#govalid-pw-body').slideUp(200);
			}
		});

		// Password type radio — show/hide unique inputs.
		$('#govalid-generate-qr-modal input[name="govalid_pw_type"]').on('change', function () {
			if ($(this).val() === 'unique') {
				$('#govalid-pw-unique-container').slideDown(200);
			} else {
				$('#govalid-pw-unique-container').slideUp(200);
			}
		});

		// Password visibility toggle.
		$('#govalid-generate-qr-modal').on('click', '.govalid-pw-vis-toggle', function (e) {
			e.stopPropagation();
			var $input = $(this).closest('div').find('input[type="password"], input[type="text"]');
			var $icon = $(this).find('.dashicons');
			if ($input.attr('type') === 'password') {
				$input.attr('type', 'text');
				$icon.removeClass('dashicons-visibility').addClass('dashicons-hidden');
			} else {
				$input.attr('type', 'password');
				$icon.removeClass('dashicons-hidden').addClass('dashicons-visibility');
			}
		});

		// Password strength indicator.
		$('#govalid-pw-input').on('input', function () {
			var val = $(this).val();
			var $bar = $('#govalid-pw-strength-bar');
			var strength = 0;
			if (val.length >= 6) strength++;
			if (val.length >= 10) strength++;
			if (/[A-Z]/.test(val) && /[a-z]/.test(val)) strength++;
			if (/\d/.test(val)) strength++;
			if (/[!@#$%^&*]/.test(val)) strength++;
			var colors = ['#dc2626', '#f97316', '#eab308', '#84cc16', '#22c55e'];
			if (strength === 0) {
				$bar.css({ width: '0%', background: 'transparent' });
			} else {
				$bar.css({ width: (strength * 20) + '%', background: colors[strength - 1] });
			}
		});

		// Select all / Deselect all fields.
		$('#govalid-fields-select-all').on('click', function (e) {
			e.preventDefault();
			$('.govalid-qr-field-check').prop('checked', true);
		});
		$('#govalid-fields-deselect-all').on('click', function (e) {
			e.preventDefault();
			$('.govalid-qr-field-check').prop('checked', false);
		});

		// Close modal.
		$('#govalid-generate-qr-modal').on('click', function (e) {
			if (e.target === this || $(e.target).hasClass('govalid-modal-close') || $(e.target).hasClass('govalid-modal-cancel')) {
				$(this).remove();
			}
		});

		// Confirm generation.
		$('#govalid-confirm-generate-qr').on('click', function () {
			var $btn = $(this);
			var qrName = $('#govalid-custom-qr-name').val().trim() || 'Form Submission';
			var securityLevel = $('#govalid-generate-qr-modal .govalid-modal-security-card.active').data('level') || 'SMART';

			// Collect checked field labels.
			var selectedFields = [];
			$('.govalid-qr-field-check:checked').each(function () {
				selectedFields.push($(this).val());
			});

			if (!selectedFields.length) {
				alert('Please select at least one field to include.');
				return;
			}

			// Collect password protection settings.
			var isPasswordProtected = $('#govalid-pw-toggle').prop('checked');
			var passwordType = 'master';
			var password = '';

			if (isPasswordProtected) {
				passwordType = $('#govalid-generate-qr-modal input[name="govalid_pw_type"]:checked').val() || 'master';
				if (passwordType === 'unique') {
					password = $('#govalid-pw-input').val();
					var passwordConfirm = $('#govalid-pw-confirm').val();
					if (!password || password.length < 6) {
						alert('Password must be at least 6 characters.');
						return;
					}
					if (password !== passwordConfirm) {
						alert('Passwords do not match.');
						return;
					}
				}
			}

			$btn.prop('disabled', true).html('<span class="dashicons dashicons-update govalid-spin" style="margin-top:4px;"></span> Generating...');

			var payload = {
				submission_ids: selectedIds,
				selected_fields: selectedFields,
				security_level: securityLevel,
				qr_name: qrName
			};

			if (isPasswordProtected) {
				payload.is_password_protected = true;
				payload.password_type = passwordType;
				if (passwordType === 'unique' && password) {
					payload.password = password;
				}
			}

			$.ajax({
				url: govalidQR.restUrl + 'generate-custom-qr',
				method: 'POST',
				contentType: 'application/json',
				data: JSON.stringify(payload),
				beforeSend: function (xhr) {
					xhr.setRequestHeader('X-WP-Nonce', govalidQR.nonce);
				},
				success: function (response) {
					$('#govalid-generate-qr-modal').remove();

					if (response.created > 0) {
						window.location.href = adminUrl('admin.php?page=govalid-qr-list&bulk_created=' + response.created);
					} else {
						alert('Generation failed: ' + (response.errors || []).join(', '));
					}
				},
				error: function (xhr) {
					var errMsg = xhr.responseJSON && xhr.responseJSON.message ? xhr.responseJSON.message : 'An error occurred.';
					alert('Error: ' + errMsg);
					$btn.prop('disabled', false).html('<span class="dashicons dashicons-screenoptions" style="margin-top:4px;"></span> Generate ' + count + ' QR Code' + (count > 1 ? 's' : ''));
				}
			});
		});
	}

	/* ------------------------------------------------------------------
	 * Submission detail modal
	 * ----------------------------------------------------------------*/

	function viewSubmission(id) {
		$.ajax({
			url: govalidQR.restUrl + 'submissions/' + id,
			method: 'GET',
			beforeSend: function (xhr) {
				xhr.setRequestHeader('X-WP-Nonce', govalidQR.nonce);
			},
			success: function (sub) {
				var html = '<div class="govalid-modal-overlay" id="govalid-sub-modal">';
				html += '<div class="govalid-modal-content" style="max-width:520px;">';
				html += '<button class="govalid-modal-close">&times;</button>';
				html += '<h3 style="margin:0 0 16px;">Submission #' + sub.id + '</h3>';
				html += '<p style="font-size:12px; color:var(--gv-gray-400); margin-bottom:16px;">' + esc(sub.created_at) + ' &middot; IP: ' + esc(sub.ip_address) + '</p>';

				(sub.values || []).forEach(function (v) {
					html += '<div style="margin-bottom:12px;">';
					html += '<div style="font-size:12px; font-weight:600; color:var(--gv-gray-600);">' + esc(v.field_label) + '</div>';
					html += '<div style="font-size:14px; color:var(--gv-gray-800); margin-top:2px;">' + renderFieldValue(v.field_value || '—', true) + '</div>';
					html += '</div>';
				});

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

				$('body').append(html);

				$('#govalid-sub-modal').on('click', function (e) {
					if (e.target === this || $(e.target).hasClass('govalid-modal-close')) {
						$(this).remove();
					}
				});
			}
		});
	}

	function deleteSubmission(id, cb) {
		$.ajax({
			url: govalidQR.restUrl + 'submissions/' + id,
			method: 'DELETE',
			beforeSend: function (xhr) {
				xhr.setRequestHeader('X-WP-Nonce', govalidQR.nonce);
			},
			success: function () { if (cb) cb(); }
		});
	}

	/* ------------------------------------------------------------------
	 * Export CSV
	 * ----------------------------------------------------------------*/

	window.govalidExportCSV = function (formId) {
		$.ajax({
			url: govalidQR.restUrl + 'forms/' + formId + '/export',
			method: 'POST',
			beforeSend: function (xhr) {
				xhr.setRequestHeader('X-WP-Nonce', govalidQR.nonce);
			},
			success: function (data) {
				if (!data.rows || !data.rows.length) {
					alert('No submissions to export.');
					return;
				}

				// Build CSV.
				var headers = Object.keys(data.rows[0]);
				var csv = headers.join(',') + '\n';
				data.rows.forEach(function (row) {
					csv += headers.map(function (h) {
						var val = (row[h] || '').toString().replace(/"/g, '""');
						return '"' + val + '"';
					}).join(',') + '\n';
				});

				// Download.
				var blob = new Blob([csv], { type: 'text/csv' });
				var url  = URL.createObjectURL(blob);
				var a    = document.createElement('a');
				a.href     = url;
				a.download = 'form-' + formId + '-submissions.csv';
				document.body.appendChild(a);
				a.click();
				document.body.removeChild(a);
				URL.revokeObjectURL(url);
			}
		});
	};

	/* ------------------------------------------------------------------
	 * Helpers
	 * ----------------------------------------------------------------*/

	function adminUrl(path) {
		// govalidQR.ajaxUrl gives us /wp-admin/admin-ajax.php.
		return govalidQR.ajaxUrl.replace('admin-ajax.php', '') + path;
	}

	function getSiteUrl() {
		return govalidQR.restUrl.replace('/wp-json/govalid-qr/v1/', '');
	}

	function esc(str) {
		var div = document.createElement('div');
		div.appendChild(document.createTextNode(str || ''));
		return div.innerHTML;
	}

	function truncate(str, len) {
		str = str || '';
		return str.length > len ? str.substring(0, len) + '...' : str;
	}

	/**
	 * Detect if a value is a file URL and render accordingly.
	 *
	 * @param {string}  val     The field value.
	 * @param {boolean} large   If true, render a larger preview (for detail modal).
	 * @return {string} HTML string.
	 */
	function renderFieldValue(val, large) {
		if (!val) return esc('—');

		// Check if value looks like an uploaded file URL.
		if (/^https?:\/\/.+/i.test(val)) {
			var lower = val.toLowerCase();
			// Image.
			if (/\.(jpe?g|png|webp|gif)$/i.test(lower)) {
				if (large) {
					return '<img src="' + esc(val) + '" style="max-width:100%; max-height:260px; border-radius:8px; margin-top:4px;" />';
				}
				return '<img src="' + esc(val) + '" class="govalid-sub-thumbnail" data-full="' + esc(val) + '" title="Click to view" />';
			}
			// PDF.
			if (/\.pdf$/i.test(lower)) {
				var fname = val.split('/').pop();
				return '<a href="' + esc(val) + '" target="_blank" class="govalid-sub-file-link">' +
					'<span class="dashicons dashicons-media-document"></span> ' + esc(fname) + '</a>';
			}
		}

		return esc(truncate(val, 50));
	}

	/* ------------------------------------------------------------------
	 * Image lightbox for thumbnails
	 * ----------------------------------------------------------------*/

	$(document).on('click', '.govalid-sub-thumbnail', function () {
		var src = $(this).data('full') || $(this).attr('src');
		var html = '<div class="govalid-modal-overlay" id="govalid-image-lightbox">';
		html += '<div class="govalid-modal-content" style="max-width:700px; padding:12px; text-align:center;">';
		html += '<button class="govalid-modal-close">&times;</button>';
		html += '<img src="' + esc(src) + '" style="max-width:100%; max-height:80vh; border-radius:8px;" />';
		html += '</div></div>';
		$('body').append(html);

		$('#govalid-image-lightbox').on('click', function (e) {
			if (e.target === this || $(e.target).hasClass('govalid-modal-close')) {
				$(this).remove();
			}
		});
	});

})(jQuery);
