(function ($) {
	'use strict';

	if (!$ || typeof wppsEmailDelivery === 'undefined') {
		return;
	}

	function showFeedback($el, ok, html) {
		var cls = ok ? 'notice-success' : 'notice-error';
		$el.html('<div class="notice ' + cls + ' inline"><p>' + html + '</p></div>').show();
	}

	function escapeHtml(str) {
		return String(str)
			.replace(/&/g, '&amp;')
			.replace(/</g, '&lt;')
			.replace(/>/g, '&gt;')
			.replace(/"/g, '&quot;');
	}

	function copyText(text) {
		if (navigator.clipboard && navigator.clipboard.writeText) {
			return navigator.clipboard.writeText(text);
		}
		var ta = document.createElement('textarea');
		ta.value = text;
		ta.setAttribute('readonly', '');
		ta.style.position = 'absolute';
		ta.style.left = '-9999px';
		document.body.appendChild(ta);
		ta.select();
		try {
			document.execCommand('copy');
		} catch (e) {}
		document.body.removeChild(ta);
		return Promise.resolve();
	}

	function bindSmtpAuthToggle($root) {
		var $auth = $root.find('#wpps_ed_smtp_auth');
		if (!$auth.length) {
			return;
		}
		var toggleAuth = function () {
			$root.find('.wpps-ed-auth-row').toggle($auth.is(':checked'));
		};
		$auth.off('change.wppsEd').on('change.wppsEd', toggleAuth);
		toggleAuth();
	}

	function bindAwsCredentialToggle($root) {
		var $source = $root.find('#wpps_ed_aws_credential_source');
		if (!$source.length) {
			return;
		}
		var toggleAws = function () {
			var useEnv = $source.val() === 'env';
			$root.find('.wpps-ed-aws-keys-row').toggle(!useEnv);
			$root.find('.wpps-ed-aws-env-row').toggle(useEnv);
		};
		$source.off('change.wppsEdAws').on('change.wppsEdAws', toggleAws);
		toggleAws();
	}

	function openHelpModal(id) {
		var $modal = $('#wpps-ed-help-modal-' + id);
		if (!$modal.length) {
			return;
		}
		$modal.addClass('is-open').attr('aria-hidden', 'false');
		$('body').addClass('wpps-ed-modal-open');
	}

	function closeHelpModal($modal) {
		if (!$modal || !$modal.length) {
			return;
		}
		$modal.removeClass('is-open').attr('aria-hidden', 'true');
		if (!$('.wpps-ed-modal.is-open').length) {
			$('body').removeClass('wpps-ed-modal-open');
		}
	}

	function bindConnectionForm($root) {
		bindSmtpAuthToggle($root);
		bindAwsCredentialToggle($root);
	}

	function settingsPageUrl() {
		return wppsEmailDelivery.settingsUrl || tabUrl('settings');
	}

	function tabUrl(tab) {
		var base = wppsEmailDelivery.pageUrl || window.location.href.split('&')[0];
		var url = base;
		try {
			var u = new URL(base, window.location.origin);
			u.searchParams.set('tab', tab);
			u.searchParams.delete('connection');
			u.searchParams.delete('provider');
			return u.toString();
		} catch (e) {
			url += (url.indexOf('?') === -1 ? '?' : '&') + 'tab=' + encodeURIComponent(tab);
			return url;
		}
	}

	function hasConnections() {
		return $('#wpps-ed-add-panel').attr('data-has-connections') === '1';
	}

	function showAddPanel() {
		$('#wpps-ed-connections-panel').prop('hidden', true);
		$('#wpps-ed-add-panel').prop('hidden', false);
	}

	function showConnectionsPanel() {
		if (!hasConnections()) {
			return;
		}
		$('#wpps-ed-add-panel').prop('hidden', true);
		$('#wpps-ed-connections-panel').prop('hidden', false);
		$('#wpps-ed-connection-form-mount').empty();
		$('.wpps-ed-provider-tile').removeClass('is-active');
		$('.wpps-ed-connections-table tr').removeClass('is-editing');
		if (window.history && window.history.replaceState) {
			window.history.replaceState({ wppsEdTab: 'settings' }, '', settingsPageUrl());
		}
	}

	function setActiveProvider(provider, connection) {
		$('.wpps-ed-provider-tile').removeClass('is-active');
		$('.wpps-ed-connections-table tr').removeClass('is-editing');
		if (connection) {
			$('.wpps-ed-edit-connection[data-connection="' + connection + '"]')
				.closest('tr')
				.addClass('is-editing');
		} else if (provider) {
			$('.wpps-ed-provider-tile[data-provider="' + provider + '"]').addClass('is-active');
		}
	}

	function clearConnectionForm() {
		$('#wpps-ed-connection-form-mount').empty();
		setActiveProvider('', '');
		if (hasConnections()) {
			showConnectionsPanel();
		} else if (window.history && window.history.replaceState) {
			window.history.replaceState({ wppsEdTab: 'settings' }, '', settingsPageUrl());
		}
	}

	function loadConnectionForm(opts) {
		var provider = opts.provider || '';
		var connection = opts.connection || '';
		var $mount = $('#wpps-ed-connection-form-mount');
		if (!$mount.length) {
			return;
		}

		if (!connection) {
			showAddPanel();
		} else {
			// Editing keeps the connections table visible.
			$('#wpps-ed-connections-panel').prop('hidden', false);
			$('#wpps-ed-add-panel').prop('hidden', true);
		}

		$mount.html(
			'<div class="wpps-ed-panel"><div class="wpps-ed-panel-body"><p class="description">' +
				escapeHtml(wppsEmailDelivery.i18n.loading || 'Loading…') +
				'</p></div></div>'
		);
		setActiveProvider(provider, connection);

		$.post(wppsEmailDelivery.ajaxUrl, {
			action: 'wpps_email_delivery_connection_form',
			nonce: wppsEmailDelivery.nonce,
			provider: provider,
			connection: connection
		})
			.done(function (res) {
				if (!(res && res.success && res.data && res.data.html)) {
					var msg =
						(res && res.data && res.data.message) || wppsEmailDelivery.i18n.error;
					$mount.html(
						'<div class="notice notice-error inline"><p>' + escapeHtml(msg) + '</p></div>'
					);
					return;
				}

				$mount.html(res.data.html);
				bindConnectionForm($mount);

				var formEl = $mount.find('#wpps-ed-connection-form')[0];
				if (formEl && formEl.scrollIntoView) {
					formEl.scrollIntoView({ behavior: 'smooth', block: 'start' });
				}

				if (window.history && window.history.replaceState) {
					var url = settingsPageUrl();
					try {
						var u = new URL(url, window.location.origin);
						if (res.data.connection) {
							u.searchParams.set('connection', res.data.connection);
						} else if (res.data.provider) {
							u.searchParams.set('provider', res.data.provider);
						}
						url = u.toString();
					} catch (e) {
						if (res.data.connection) {
							url +=
								(url.indexOf('?') === -1 ? '?' : '&') +
								'connection=' +
								encodeURIComponent(res.data.connection);
						} else if (res.data.provider) {
							url +=
								(url.indexOf('?') === -1 ? '?' : '&') +
								'provider=' +
								encodeURIComponent(res.data.provider);
						}
					}
					window.history.replaceState({ wppsEdTab: 'settings' }, '', url);
				}
			})
			.fail(function () {
				$mount.html(
					'<div class="notice notice-error inline"><p>' +
						escapeHtml(wppsEmailDelivery.i18n.error) +
						'</p></div>'
				);
			});
	}

	$(function () {
		bindConnectionForm($(document));

		$(document).on('click', '.wpps-ed-show-add-connection', function (e) {
			e.preventDefault();
			showAddPanel();
			$('#wpps-ed-connection-form-mount').empty();
			$('.wpps-ed-provider-tile').removeClass('is-active');
		});

		$(document).on('click', '.wpps-ed-hide-add-connection', function (e) {
			e.preventDefault();
			clearConnectionForm();
		});

		$(document).on('click', '.wpps-ed-provider-tile', function (e) {
			e.preventDefault();
			var provider = $(this).data('provider') || '';
			if (!provider) {
				return;
			}
			loadConnectionForm({ provider: provider });
		});

		$(document).on('click', '.wpps-ed-edit-connection', function (e) {
			e.preventDefault();
			loadConnectionForm({
				provider: $(this).data('provider') || '',
				connection: $(this).data('connection') || ''
			});
		});

		$(document).on('click', '.wpps-ed-cancel-connection', function (e) {
			e.preventDefault();
			clearConnectionForm();
		});

		$(document).on('click', '.wpps-ed-copy', function () {
			var $btn = $(this);
			var value = $btn.attr('data-copy') || '';
			if (!value) {
				return;
			}
			copyText(value).then(function () {
				var prev = $btn.text();
				$btn.text(wppsEmailDelivery.i18n.copied || 'Copied');
				setTimeout(function () {
					$btn.text(prev);
				}, 1500);
			});
		});

		$(document).on('click', '#wpps-ed-send-test', function () {
			var $btn = $(this);
			var $fb = $('#wpps-ed-test-feedback');
			var email = $('#wpps_ed_test_email').val();
			if (!$btn.data('label')) {
				$btn.data('label', $btn.text());
			}
			$btn.prop('disabled', true).text(wppsEmailDelivery.i18n.sending);
			$fb.empty();

			$.post(wppsEmailDelivery.ajaxUrl, {
				action: 'wpps_email_delivery_test_email',
				nonce: wppsEmailDelivery.nonce,
				test_email: email,
				subject: $('#wpps_ed_test_subject').val(),
				message: $('#wpps_ed_test_message').val(),
				format: $('input[name="wpps_ed_test_format"]:checked').val()
			})
				.done(function (res) {
					var data = (res && res.data) || {};
					var msg = escapeHtml(
						data.user_message || data.message || wppsEmailDelivery.i18n.error
					);
					if (data.provider) {
						msg +=
							'<br><span class="wpps-ed-muted">Provider: ' +
							escapeHtml(data.provider) +
							'</span>';
					}
					if (data.provider_message_id) {
						msg +=
							'<br><span class="wpps-ed-muted">Message ID: ' +
							escapeHtml(data.provider_message_id) +
							'</span>';
					}
					if (typeof data.duration_ms === 'number' && data.duration_ms > 0) {
						msg +=
							'<br><span class="wpps-ed-muted">' + data.duration_ms + ' ms</span>';
					}
					if (data.technical_message && !(res && res.success)) {
						msg += '<br><code>' + escapeHtml(data.technical_message) + '</code>';
					}
					showFeedback($fb, !!(res && res.success), msg);
				})
				.fail(function () {
					showFeedback($fb, false, escapeHtml(wppsEmailDelivery.i18n.error));
				})
				.always(function () {
					$btn.prop('disabled', false).text($btn.data('label') || 'Send Test Email');
				});
		});

		function renderDomainHealth(data) {
			var $panel = $('#wpps-ed-domain-health-panel');
			if (!$panel.length) {
				return;
			}
			if (!data || !data.show) {
				$panel.remove();
				return;
			}

			var scoreTpl = wppsEmailDelivery.i18n.scoreOf || '%1$d of %2$d checks passed';
			$('#wpps-ed-dh-domain').text(data.domain || '');
			$('#wpps-ed-dh-score').text(
				scoreTpl.replace('%1$d', String(data.score || 0)).replace('%2$d', String(data.total || 0))
			);
			$('#wpps-ed-dh-checked').text(data.checked_label || wppsEmailDelivery.i18n.justNow || 'just now');

			var checks = Array.isArray(data.checks) ? data.checks : [];
			var html = checks
				.map(function (check) {
					var tip = check.tip
						? '<em class="wpps-ed-domain-health__tip">' + escapeHtml(check.tip) + '</em>'
						: '';
					return (
						'<li class="wpps-ed-domain-health__item wpps-ed-domain-health__item--' +
						escapeHtml(check.tone || 'muted') +
						'">' +
						'<strong>' +
						escapeHtml(check.label || '') +
						'</strong>' +
						'<span>' +
						escapeHtml(check.detail || '') +
						'</span>' +
						tip +
						'</li>'
					);
				})
				.join('');
			$('#wpps-ed-dh-list').html(html);
		}

		function fetchDomainHealth(force) {
			var $panel = $('#wpps-ed-domain-health-panel');
			var $btn = $('#wpps-ed-domain-health-refresh');
			if (!$panel.length) {
				return;
			}
			$btn.prop('disabled', true).text(wppsEmailDelivery.i18n.refreshing || 'Refreshing…');
			$panel.addClass('is-loading');

			$.post(wppsEmailDelivery.ajaxUrl, {
				action: 'wpps_email_delivery_domain_health',
				nonce: wppsEmailDelivery.nonce,
				force: force ? 1 : 0
			})
				.done(function (res) {
					if (res && res.success && res.data) {
						renderDomainHealth(res.data);
					}
				})
				.always(function () {
					$btn.prop('disabled', false).text($btn.data('label') || wppsEmailDelivery.i18n.refresh || 'Refresh');
					$panel.removeClass('is-loading');
				});
		}

		$(document).on('click', '#wpps-ed-domain-health-refresh', function (e) {
			e.preventDefault();
			e.stopPropagation();
			var $panel = $('#wpps-ed-domain-health-panel');
			if ($panel.length && !$panel.prop('open')) {
				$panel.prop('open', true);
			}
			fetchDomainHealth(true);
		});

		// First open of a pending panel runs a non-forced check (uses cache when available).
		$(document).on('toggle', '#wpps-ed-domain-health-panel', function () {
			var $panel = $(this);
			if (!$panel.prop('open') || $panel.data('wppsDhLoaded')) {
				return;
			}
			if ($panel.find('.wpps-ed-domain-health__item--muted').length && $('#wpps-ed-dh-list li').length <= 1) {
				$panel.data('wppsDhLoaded', 1);
				fetchDomainHealth(false);
			}
		});

		$(document).on('click', '#wpps-ed-test-connection', function () {
			var $btn = $(this);
			var $form = $btn.closest('form');
			var $fb = $('#wpps-ed-test-connection-feedback');
			if (!$fb.length) {
				$fb = $('<div id="wpps-ed-test-connection-feedback" class="wpps-ed-feedback" aria-live="polite"></div>');
				$btn.closest('p.submit').after($fb);
			}
			$btn.prop('disabled', true).text(wppsEmailDelivery.i18n.testing || 'Testing…');
			$fb.empty();

			var payload = $form.length ? $form.serializeArray() : [];
			payload.push({ name: 'action', value: 'wpps_email_delivery_test_connection' });
			payload.push({ name: 'nonce', value: wppsEmailDelivery.nonce });

			$.post(wppsEmailDelivery.ajaxUrl, $.param(payload))
				.done(function (res) {
					var data = (res && res.data) || {};
					var msg = escapeHtml(
						data.user_message || data.message || wppsEmailDelivery.i18n.error
					);
					if (data.provider) {
						msg +=
							'<br><span class="wpps-ed-muted">Provider: ' +
							escapeHtml(data.provider) +
							(data.transport ? ' (' + escapeHtml(data.transport) + ')' : '') +
							'</span>';
					}
					if (data.technical_message && !(res && res.success)) {
						msg += '<br><code>' + escapeHtml(data.technical_message) + '</code>';
					}
					showFeedback($fb, !!(res && res.success), msg);
				})
				.fail(function () {
					showFeedback($fb, false, escapeHtml(wppsEmailDelivery.i18n.error));
				})
				.always(function () {
					$btn.prop('disabled', false).text($btn.data('label') || 'Test Connection');
				});
		});

		$(document).on('click', '.wpps-ed-open-help-modal', function (e) {
			e.preventDefault();
			openHelpModal($(this).data('wpps-ed-help') || '');
		});

		$(document).on('click', '[data-wpps-ed-close]', function (e) {
			e.preventDefault();
			closeHelpModal($(this).closest('.wpps-ed-modal'));
		});

		$(document).on('click', '.wpps-ed-modal', function (e) {
			if (e.target === this) {
				closeHelpModal($(this));
			}
		});

		$(document).on('keydown', function (e) {
			if (e.key === 'Escape') {
				closeHelpModal($('.wpps-ed-modal.is-open').last());
			}
		});

		initSoftTabs();
		onTabPanelReady();
	});

	var tabRequest = null;
	var tabRequestSeq = 0;
	var currentSoftTab = '';
	var softTabFailed = false;

	function onTabPanelReady() {
		var $panel = $('#wpps-ed-tab-panel');
		bindConnectionForm($panel);
		var $sendBtn = $('#wpps-ed-send-test');
		if ($sendBtn.length) {
			$sendBtn.data('label', $sendBtn.data('label') || $sendBtn.text());
		}
		initOverviewAnalytics();
	}

	function setActiveSoftTab(tab, opts) {
		opts = opts || {};
		if (opts.commit !== false) {
			currentSoftTab = tab;
		}
		$('.wpps-ed-tabs .nav-tab[data-wpps-ed-tab]').removeClass('nav-tab-active');
		$('.wpps-ed-tabs .nav-tab[data-wpps-ed-tab="' + tab + '"]').addClass('nav-tab-active');
		$('#wpps-ed-tab-panel').attr('data-current-tab', tab);
	}

	function loadSoftTab(tab, opts) {
		opts = opts || {};
		var $panel = $('#wpps-ed-tab-panel');
		if (!$panel.length) {
			return;
		}
		tab = tab || 'settings';
		if (
			!opts.force &&
			!softTabFailed &&
			tab === currentSoftTab &&
			$panel.attr('data-current-tab') === tab
		) {
			return;
		}

		if (tabRequest && tabRequest.abort) {
			tabRequest.abort();
		}

		var seq = ++tabRequestSeq;
		softTabFailed = false;
		// Visual only until success — keep currentSoftTab so failed loads can retry.
		setActiveSoftTab(tab, { commit: false });
		$panel.addClass('is-loading').attr('aria-busy', 'true');
		$panel.html(
			'<div class="wpps-ed-panel"><div class="wpps-ed-panel-body"><p class="description">' +
				escapeHtml(wppsEmailDelivery.i18n.loading || 'Loading…') +
				'</p></div></div>'
		);

		var req = $.post(wppsEmailDelivery.ajaxUrl, {
			action: 'wpps_email_delivery_tab',
			nonce: wppsEmailDelivery.nonce,
			tab: tab
		});
		tabRequest = req;
		req
			.done(function (res) {
				if (seq !== tabRequestSeq) return;
				if (!(res && res.success && res.data && typeof res.data.html === 'string')) {
					softTabFailed = true;
					var msg =
						(res && res.data && res.data.message) || wppsEmailDelivery.i18n.error;
					$panel.html(
						'<div class="notice notice-error inline"><p>' + escapeHtml(msg) + '</p></div>'
					);
					return;
				}
				var resolved = res.data.tab || tab;
				softTabFailed = false;
				setActiveSoftTab(resolved, { commit: true });
				$panel.html(res.data.html);
				onTabPanelReady();
				if (opts.push !== false && window.history && window.history.pushState) {
					window.history.pushState(
						{ wppsEdTab: resolved },
						'',
						res.data.url || tabUrl(resolved)
					);
				} else if (opts.replace && window.history && window.history.replaceState) {
					window.history.replaceState(
						{ wppsEdTab: resolved },
						'',
						res.data.url || tabUrl(resolved)
					);
				}
			})
			.fail(function (xhr) {
				if (seq !== tabRequestSeq) return;
				if (xhr && xhr.statusText === 'abort') {
					return;
				}
				softTabFailed = true;
				$panel.html(
					'<div class="notice notice-error inline"><p>' +
						escapeHtml(wppsEmailDelivery.i18n.error) +
						'</p></div>'
				);
			})
			.always(function () {
				if (seq !== tabRequestSeq) return;
				$panel.removeClass('is-loading').attr('aria-busy', 'false');
				if (tabRequest === req) {
					tabRequest = null;
				}
			});
	}

	function initSoftTabs() {
		var $panel = $('#wpps-ed-tab-panel');
		if (!$panel.length) {
			return;
		}

		currentSoftTab = $panel.attr('data-current-tab') || 'settings';
		if (window.history && window.history.replaceState) {
			window.history.replaceState(
				{ wppsEdTab: currentSoftTab },
				'',
				window.location.href
			);
		}

		$(document).on('click', '.wpps-ed-tabs .nav-tab[data-wpps-ed-tab]', function (e) {
			var tab = $(this).attr('data-wpps-ed-tab') || '';
			if (!tab) {
				return;
			}
			// Allow open-in-new-tab / modified clicks to use normal navigation.
			if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey || e.which === 2) {
				return;
			}
			e.preventDefault();
			loadSoftTab(tab, { push: true });
		});

		$(window).on('popstate.wppsEdTabs', function (e) {
			var state = e.originalEvent && e.originalEvent.state;
			var tab = (state && state.wppsEdTab) || '';
			if (!tab) {
				try {
					tab = new URL(window.location.href).searchParams.get('tab') || 'settings';
				} catch (err) {
					tab = 'settings';
				}
			}
			if (['settings', 'overview', 'test'].indexOf(tab) === -1) {
				tab = 'settings';
			}
			loadSoftTab(tab, { push: false, force: true });
		});
	}

	var overviewStatsRequest = null;
	var overviewStatsSeq = 0;
	var overviewRangeTimer = null;
	var overviewRangeBound = false;

	function todayYmd() {
		if (wppsEmailDelivery.siteToday && /^\d{4}-\d{2}-\d{2}$/.test(wppsEmailDelivery.siteToday)) {
			return wppsEmailDelivery.siteToday;
		}
		var d = new Date();
		var m = String(d.getMonth() + 1).padStart(2, '0');
		var day = String(d.getDate()).padStart(2, '0');
		return d.getFullYear() + '-' + m + '-' + day;
	}

	function syncOverviewDateConstraints() {
		var $start = $('#wpps-ed-overview-start');
		var $end = $('#wpps-ed-overview-end');
		if (!$start.length || !$end.length) return;

		var today = todayYmd();
		var start = $start.val() || '';
		var end = $end.val() || today;

		$end.attr('max', today);
		$start.attr('max', end && end < today ? end : today);
		if (end) {
			// Match server 90-day cap for clearer UX.
			var endDate = new Date(end + 'T00:00:00');
			if (!isNaN(endDate.getTime())) {
				endDate.setDate(endDate.getDate() - 89);
				var minM = String(endDate.getMonth() + 1).padStart(2, '0');
				var minD = String(endDate.getDate()).padStart(2, '0');
				$start.attr('min', endDate.getFullYear() + '-' + minM + '-' + minD);
			}
		}
		if (start && end && start > end) {
			$start.val(end);
		}
	}

	var overviewChartState = null;
	var overviewLastSeries = null;
	var overviewResizeTimer = null;
	var overviewResizeBound = false;

	function niceMax(value) {
		var v = Math.max(1, value);
		if (v <= 5) return 5;
		var exp = Math.pow(10, Math.floor(Math.log10(v)));
		var n = Math.ceil(v / exp);
		if (n <= 2) return 2 * exp;
		if (n <= 5) return 5 * exp;
		return 10 * exp;
	}

	function formatOverviewDay(ymd) {
		var parts = String(ymd || '').split('-');
		if (parts.length !== 3) return String(ymd || '');
		return parts[1] + '/' + parts[2] + '/' + parts[0];
	}

	function areaPathFor(values, xAt, yAt, pad, height) {
		if (!values.length) return '';
		var line = values
			.map(function (v, i) {
				return (i === 0 ? 'M' : 'L') + xAt(i).toFixed(2) + ',' + yAt(v).toFixed(2);
			})
			.join(' ');
		var lastX = xAt(values.length - 1).toFixed(2);
		var firstX = xAt(0).toFixed(2);
		var baseY = (pad.top + (height - pad.top - pad.bottom)).toFixed(2);
		return line + ' L' + lastX + ',' + baseY + ' L' + firstX + ',' + baseY + ' Z';
	}

	function hideOverviewTooltip() {
		var tip = document.getElementById('wpps-ed-overview-tooltip');
		var guide = document.getElementById('wpps-ed-overview-guide');
		var sentDot = document.getElementById('wpps-ed-overview-dot-sent');
		var failDot = document.getElementById('wpps-ed-overview-dot-failed');
		if (tip) tip.hidden = true;
		if (guide) guide.setAttribute('opacity', '0');
		if (sentDot) sentDot.setAttribute('opacity', '0');
		if (failDot) failDot.setAttribute('opacity', '0');
	}

	function showOverviewPoint(index) {
		var state = overviewChartState;
		var tip = document.getElementById('wpps-ed-overview-tooltip');
		var wrap = document.querySelector('.wpps-ed-overview-chart-wrap');
		var svg = document.getElementById('wpps-ed-overview-chart');
		var guide = document.getElementById('wpps-ed-overview-guide');
		var sentDot = document.getElementById('wpps-ed-overview-dot-sent');
		var failDot = document.getElementById('wpps-ed-overview-dot-failed');
		if (!state || !tip || !wrap || !svg || index < 0 || index >= state.n) {
			hideOverviewTooltip();
			return;
		}

		var x = state.xAt(index);
		var sentY = state.yAt(state.sent[index] || 0);
		var failY = state.yAt(state.failed[index] || 0);
		var i18n = wppsEmailDelivery.i18n || {};

		if (guide) {
			guide.setAttribute('x1', x.toFixed(2));
			guide.setAttribute('x2', x.toFixed(2));
			guide.setAttribute('opacity', '1');
		}
		if (sentDot) {
			sentDot.setAttribute('cx', x.toFixed(2));
			sentDot.setAttribute('cy', sentY.toFixed(2));
			sentDot.setAttribute('opacity', '1');
		}
		if (failDot) {
			failDot.setAttribute('cx', x.toFixed(2));
			failDot.setAttribute('cy', failY.toFixed(2));
			failDot.setAttribute('opacity', '1');
		}

		tip.innerHTML =
			'<p class="wpps-ed-overview-tooltip__date">' +
			escapeHtml(formatOverviewDay(state.labels[index])) +
			'</p>' +
			'<p class="wpps-ed-overview-tooltip__row"><span><span class="wpps-ed-overview-tooltip__swatch" style="background:#2f80ed"></span>' +
			escapeHtml(i18n.emailSent || 'Emails sent') +
			'</span><strong>' +
			escapeHtml(String(state.sent[index] || 0)) +
			'</strong></p>' +
			'<p class="wpps-ed-overview-tooltip__row"><span><span class="wpps-ed-overview-tooltip__swatch" style="background:#9b51e0"></span>' +
			escapeHtml(i18n.emailFailed || 'Emails failed') +
			'</span><strong>' +
			escapeHtml(String(state.failed[index] || 0)) +
			'</strong></p>';
		tip.hidden = false;

		var rect = svg.getBoundingClientRect();
		var wrapRect = wrap.getBoundingClientRect();
		var scaleX = rect.width / state.width;
		var scaleY = rect.height / state.height;
		var left = rect.left - wrapRect.left + x * scaleX;
		var top = rect.top - wrapRect.top + Math.min(sentY, failY) * scaleY;
		var tipWidth = tip.offsetWidth || 160;
		left = Math.max(tipWidth / 2 + 8, Math.min(wrapRect.width - tipWidth / 2 - 8, left));
		tip.style.left = left + 'px';
		tip.style.top = Math.max(12, top) + 'px';
	}

	function bindOverviewChartInteraction(svg) {
		if (!svg || svg.getAttribute('data-wpps-ed-bound') === '1') return;
		svg.setAttribute('data-wpps-ed-bound', '1');

		svg.addEventListener('mousemove', function (e) {
			var state = overviewChartState;
			if (!state || !state.n) return;
			var rect = svg.getBoundingClientRect();
			var px = ((e.clientX - rect.left) / Math.max(1, rect.width)) * state.width;
			var idx = 0;
			if (state.n > 1) {
				idx = Math.round(((px - state.pad.left) / state.innerW) * (state.n - 1));
				idx = Math.max(0, Math.min(state.n - 1, idx));
			}
			showOverviewPoint(idx);
		});

		svg.addEventListener('mouseleave', hideOverviewTooltip);
		svg.addEventListener(
			'touchstart',
			function (e) {
				if (!e.touches || !e.touches[0] || !overviewChartState) return;
				var touch = e.touches[0];
				var rect = svg.getBoundingClientRect();
				var px = ((touch.clientX - rect.left) / Math.max(1, rect.width)) * overviewChartState.width;
				var idx = 0;
				if (overviewChartState.n > 1) {
					idx = Math.round(
						((px - overviewChartState.pad.left) / overviewChartState.innerW) *
							(overviewChartState.n - 1)
					);
					idx = Math.max(0, Math.min(overviewChartState.n - 1, idx));
				}
				showOverviewPoint(idx);
			},
			{ passive: true }
		);
	}

	function bindOverviewChartResize() {
		if (overviewResizeBound) return;
		overviewResizeBound = true;
		window.addEventListener('resize', function () {
			clearTimeout(overviewResizeTimer);
			overviewResizeTimer = setTimeout(function () {
				if (overviewLastSeries) {
					renderOverviewChart(overviewLastSeries);
				}
			}, 120);
		});
	}

	function renderOverviewChart(series) {
		var svg = document.getElementById('wpps-ed-overview-chart');
		var empty = document.getElementById('wpps-ed-overview-empty');
		var sentEl = document.getElementById('wpps-ed-overview-sent-total');
		var failEl = document.getElementById('wpps-ed-overview-failed-total');
		if (!svg || !series) return;

		overviewLastSeries = series;
		bindOverviewChartResize();

		var labels = series.labels || [];
		var sent = (series.sent || []).map(function (n) { return Number(n) || 0; });
		var failed = (series.failed || []).map(function (n) { return Number(n) || 0; });
		var totals = series.totals || {};
		var sentTotal = Number(totals.sent);
		var failTotal = Number(totals.failed);
		if (!Number.isFinite(sentTotal)) {
			sentTotal = sent.reduce(function (a, b) { return a + b; }, 0);
		}
		if (!Number.isFinite(failTotal)) {
			failTotal = failed.reduce(function (a, b) { return a + b; }, 0);
		}

		if (sentEl) sentEl.textContent = String(sentTotal);
		if (failEl) failEl.textContent = String(failTotal);

		var wrap = svg.parentElement;
		var height = 280;
		// Match viewBox to the visible wrap so the plot fills the card (no side letterboxing).
		var width = wrap ? Math.max(320, Math.round(wrap.clientWidth) || wrap.offsetWidth || 960) : 960;
		if (window.matchMedia && window.matchMedia('(max-width: 600px)').matches) {
			height = 220;
		}
		var pad = { top: 16, right: 12, bottom: 30, left: 36 };
		var innerW = Math.max(40, width - pad.left - pad.right);
		var innerH = Math.max(40, height - pad.top - pad.bottom);
		var maxRaw = Math.max.apply(null, sent.concat(failed).concat([0]));
		var maxY = niceMax(maxRaw);
		var n = Math.max(labels.length, 1);
		var hasData = sentTotal + failTotal > 0;

		if (empty) empty.hidden = hasData;
		hideOverviewTooltip();

		function xAt(i) {
			if (n <= 1) return pad.left + innerW / 2;
			return pad.left + (innerW * i) / (n - 1);
		}
		function yAt(v) {
			return pad.top + innerH - (innerH * v) / maxY;
		}
		function pathFor(values) {
			if (!values.length) return '';
			return values
				.map(function (v, i) {
					return (i === 0 ? 'M' : 'L') + xAt(i).toFixed(2) + ',' + yAt(v).toFixed(2);
				})
				.join(' ');
		}

		overviewChartState = {
			labels: labels,
			sent: sent,
			failed: failed,
			n: n,
			width: width,
			height: height,
			pad: pad,
			innerW: innerW,
			xAt: xAt,
			yAt: yAt
		};

		var grid = '';
		var yLabels = '';
		var ticks = 4;
		for (var t = 0; t <= ticks; t++) {
			var value = Math.round((maxY * (ticks - t)) / ticks);
			var gy = pad.top + (innerH * t) / ticks;
			grid +=
				'<line x1="' +
				pad.left +
				'" y1="' +
				gy.toFixed(2) +
				'" x2="' +
				(width - pad.right) +
				'" y2="' +
				gy.toFixed(2) +
				'" stroke="#eceef1" stroke-width="1" />';
			yLabels +=
				'<text x="' +
				(pad.left - 8) +
				'" y="' +
				(gy + 3).toFixed(2) +
				'" text-anchor="end" fill="#8c8f94" font-size="11">' +
				escapeHtml(String(value)) +
				'</text>';
		}

		var xLabels = '';
		var labelStep = Math.max(1, Math.ceil(n / 8));
		for (var i = 0; i < n; i++) {
			if (i % labelStep !== 0 && i !== n - 1) continue;
			var d = String(labels[i] || '');
			var short = d.length >= 10 ? d.slice(5, 7) + '/' + d.slice(8, 10) : d;
			xLabels +=
				'<text x="' +
				xAt(i).toFixed(2) +
				'" y="' +
				(height - 10) +
				'" text-anchor="middle" fill="#8c8f94" font-size="11">' +
				escapeHtml(short) +
				'</text>';
		}

		svg.setAttribute('viewBox', '0 0 ' + width + ' ' + height);
		svg.setAttribute('preserveAspectRatio', 'none');
		svg.setAttribute('width', '100%');
		svg.setAttribute('height', String(height));
		svg.innerHTML =
			'<defs>' +
			'<linearGradient id="wpps-ed-sent-fill" x1="0" y1="0" x2="0" y2="1">' +
			'<stop offset="0%" stop-color="#2f80ed" stop-opacity="0.22"/>' +
			'<stop offset="100%" stop-color="#2f80ed" stop-opacity="0.02"/>' +
			'</linearGradient>' +
			'<linearGradient id="wpps-ed-failed-fill" x1="0" y1="0" x2="0" y2="1">' +
			'<stop offset="0%" stop-color="#9b51e0" stop-opacity="0.18"/>' +
			'<stop offset="100%" stop-color="#9b51e0" stop-opacity="0.02"/>' +
			'</linearGradient>' +
			'</defs>' +
			grid +
			yLabels +
			'<path d="' +
			areaPathFor(sent, xAt, yAt, pad, height) +
			'" fill="url(#wpps-ed-sent-fill)" stroke="none" />' +
			'<path d="' +
			areaPathFor(failed, xAt, yAt, pad, height) +
			'" fill="url(#wpps-ed-failed-fill)" stroke="none" />' +
			'<path d="' +
			pathFor(sent) +
			'" fill="none" stroke="#2f80ed" stroke-width="2.75" stroke-linecap="round" stroke-linejoin="round" />' +
			'<path d="' +
			pathFor(failed) +
			'" fill="none" stroke="#9b51e0" stroke-width="2.75" stroke-linecap="round" stroke-linejoin="round" />' +
			xLabels +
			'<line id="wpps-ed-overview-guide" x1="0" y1="' +
			pad.top +
			'" x2="0" y2="' +
			(pad.top + innerH) +
			'" stroke="#94a3b8" stroke-width="1" stroke-dasharray="3 3" opacity="0" />' +
			'<circle id="wpps-ed-overview-dot-sent" r="4.5" fill="#2f80ed" stroke="#fff" stroke-width="2" opacity="0" />' +
			'<circle id="wpps-ed-overview-dot-failed" r="4.5" fill="#9b51e0" stroke="#fff" stroke-width="2" opacity="0" />';

		bindOverviewChartInteraction(svg);
	}

	function refreshOverviewFromInputs() {
		var $root = $('#wpps-ed-overview-analytics');
		var $start = $('#wpps-ed-overview-start');
		var $end = $('#wpps-ed-overview-end');
		if (!$root.length || !$start.length || !$end.length) return;

		syncOverviewDateConstraints();

		var start = $start.val();
		var end = $end.val();
		if (!start || !end) return;
		if (start > end) {
			var tmp = start;
			start = end;
			end = tmp;
			$start.val(start);
			$end.val(end);
			syncOverviewDateConstraints();
		}

		var prevStart = $root.attr('data-start') || '';
		var prevEnd = $root.attr('data-end') || '';
		if (start === prevStart && end === prevEnd && $root.attr('data-loaded') === '1') {
			return;
		}

		if (overviewStatsRequest && overviewStatsRequest.abort) {
			overviewStatsRequest.abort();
		}

		var seq = ++overviewStatsSeq;
		$root.addClass('is-loading');
		overviewStatsRequest = $.post(wppsEmailDelivery.ajaxUrl, {
			action: 'wpps_email_delivery_overview_stats',
			nonce: wppsEmailDelivery.nonce,
			start: start,
			end: end
		})
			.done(function (res) {
				if (seq !== overviewStatsSeq) return;
				if (!(res && res.success && res.data)) {
					if (prevStart) $start.val(prevStart);
					if (prevEnd) $end.val(prevEnd);
					syncOverviewDateConstraints();
					return;
				}

				renderOverviewChart(res.data);
				var nextStart = res.data.start || start;
				var nextEnd = res.data.end || end;
				$root.attr('data-start', nextStart);
				$root.attr('data-end', nextEnd);
				$root.attr('data-loaded', '1');
				if (nextStart) $start.val(nextStart);
				if (nextEnd) $end.val(nextEnd);
				syncOverviewDateConstraints();
			})
			.fail(function (xhr) {
				if (seq !== overviewStatsSeq) return;
				if (xhr && xhr.statusText === 'abort') return;
				if (prevStart) $start.val(prevStart);
				if (prevEnd) $end.val(prevEnd);
				syncOverviewDateConstraints();
			})
			.always(function () {
				if (seq !== overviewStatsSeq) return;
				$root.removeClass('is-loading');
				overviewStatsRequest = null;
			});
	}

	function scheduleOverviewRefresh() {
		clearTimeout(overviewRangeTimer);
		overviewRangeTimer = setTimeout(refreshOverviewFromInputs, 200);
	}

	function bindOverviewRangeControls() {
		if (overviewRangeBound) return;
		overviewRangeBound = true;
		$(document).on(
			'change.wppsEdOverview input.wppsEdOverview',
			'#wpps-ed-overview-start, #wpps-ed-overview-end',
			scheduleOverviewRefresh
		);
	}

	function initOverviewAnalytics() {
		var $root = $('#wpps-ed-overview-analytics');
		if (!$root.length) return;

		bindOverviewRangeControls();
		syncOverviewDateConstraints();

		var dataEl = document.getElementById('wpps-ed-overview-series-data');
		var series = null;
		if (dataEl && dataEl.textContent) {
			try {
				series = JSON.parse(dataEl.textContent);
			} catch (e) {
				series = null;
			}
		}
		if (series) {
			renderOverviewChart(series);
			if (series.start) {
				$root.attr('data-start', series.start);
				$('#wpps-ed-overview-start').val(series.start);
			}
			if (series.end) {
				$root.attr('data-end', series.end);
				$('#wpps-ed-overview-end').val(series.end);
			}
			$root.attr('data-loaded', '1');
			syncOverviewDateConstraints();
		}
	}
})(jQuery);
