/**
 * PS_Label_Debug — browser-side viewer (verbose edition).
 *
 * What you see in F12 after opening a WC order page:
 *   1. **PS-LABEL trail** — collapsible group polled every 5 s. Merged timeline
 *      of every server-side event (AJAX, webhook, VPS, format-mismatch).
 *   2. **PS-LABEL xhr / fetch** — every outbound HTTP call from this page:
 *      method, URL, request body (redacted), HTTP code, duration, response
 *      body head, any `_debug` trail the response carried.
 *   3. **PS-LABEL iframe** — URL + parsed query params of the VPS iframe.
 *   4. **PS-LABEL postMessage** — any message the VPS iframe sends the parent
 *      page (session state transitions, payment detection, ready states).
 *   5. **PS-LABEL format-alert** — pops in orange when a response is missing
 *      required keys (detected server-side by Parcselect_Label_Debug::validate_format).
 *
 * Every log entry carries `order_id`, `session_id`, and `request_id` so the
 * full flow (session create → SOL payment → webhook → download) can be
 * traced through one grep in the devtools console.
 */
(function () {
	'use strict';
	if (typeof window === 'undefined' || !window.ParcselectLabelDebug) {
		return;
	}
	var cfg = window.ParcselectLabelDebug;
	if (!cfg.order_id || !cfg.ajax_url || !cfg.nonce) {
		return;
	}

	var seen = {};
	var seenCount = 0;
	var pollMs = cfg.poll_ms || 5000;

	function rememberSeen(key) {
		if (seen[key]) return true;
		if (seenCount > 800) { seen = {}; seenCount = 0; }
		seen[key] = 1; seenCount++;
		return false;
	}

	function badge(bg, color) {
		color = color || '#fff';
		return 'color:' + color + ';background:' + bg + ';padding:2px 7px;border-radius:3px;font-weight:600;';
	}

	function style(level) {
		switch (level) {
			case 'error':   return badge('#dc2626');
			case 'warning': return badge('#fbbf24', '#000');
			default:        return badge('#2563eb');
		}
	}

	function shortId(s) {
		if (!s) return '';
		s = String(s);
		if (s.length <= 16) return s;
		return s.slice(0, 8) + '…' + s.slice(-4);
	}

	function printEntry(e) {
		if (!e || !e.event) return;
		var key = (e.ts || '') + '|' + e.event + '|' + (e.order_id || '') + '|' + (e.request_id || '');
		if (rememberSeen(key)) return;
		var when = e.ts ? new Date(e.ts).toLocaleTimeString() : '--:--:--';
		var tag  = 'PS-LABEL';
		var corr = 'o=' + (e.order_id || '-') +
			' sid=' + shortId(e.session_id) +
			' rid=' + (e.request_id || '-');

		// Format-mismatch events get a loud orange banner so nobody misses them.
		if (e.event.indexOf('format.mismatch') !== -1) {
			console.log('%c⚠ FORMAT MISMATCH%c ' + when + ' · ' + e.event + ' · ' + corr,
				badge('#f97316'), '', e.data || {});
			return;
		}

		console.log(
			'%c' + tag + '%c ' + when + ' · ' + e.event + ' · ' + corr,
			style(e.level), '',
			e.data || {}
		);
	}

	function fetchTrail() {
		var body = new FormData();
		body.append('action', 'parcselect_label_debug_trail');
		body.append('nonce', cfg.nonce);
		body.append('order_id', cfg.order_id);
		// Mark our own trail-fetch request so the xhr wrapper below can skip
		// logging it (otherwise we'd log an infinite regress of trail polls).
		body.append('_ps_debug_internal', '1');
		fetch(cfg.ajax_url, { method: 'POST', credentials: 'same-origin', body: body })
			.then(function (r) { return r.json(); })
			.then(function (j) {
				if (!j || !j.success || !j.data) return;
				var trail = j.data.trail || [];
				if (trail.length === 0) return;
				console.groupCollapsed('%cPS-LABEL trail%c order=' + cfg.order_id + ' (' + trail.length + ')',
					badge('#0891b2'), '');
				trail.forEach(printEntry);
				console.groupEnd();
			})
			.catch(function (err) {
				console.warn('[PS-LABEL] trail fetch failed:', err);
			});
	}

	// ── 1. jQuery AJAX wrapper — every parcselect_label_* AJAX call fully dumped ──
	if (window.jQuery) {
		window.jQuery(document).ajaxSend(function (ev, xhr, settings) {
			// Stash start time on the XHR so ajaxComplete can compute duration.
			try { xhr._ps_t0 = Date.now(); xhr._ps_url = settings.url; xhr._ps_data = settings.data; } catch (e) {}
		});
		window.jQuery(document).ajaxComplete(function (ev, xhr, settings) {
			try {
				var url  = settings.url || xhr._ps_url || '';
				var data = settings.data || xhr._ps_data || '';
				var action = '';
				if (typeof data === 'string') {
					var m = data.match(/action=([^&]+)/);
					if (m) action = decodeURIComponent(m[1]);
				} else if (data && data.action) {
					action = data.action;
				}
				// Filter to parcselect_label_* and our trail poll (hidden with _ps_debug_internal=1).
				var isOurs = action && action.indexOf('parcselect_label_') === 0;
				var isInternal = typeof data === 'string' && data.indexOf('_ps_debug_internal=1') !== -1;
				if (!isOurs || isInternal) return;

				var dur = xhr._ps_t0 ? (Date.now() - xhr._ps_t0) : null;
				var ct  = xhr.getResponseHeader('content-type') || '';
				var body = null;
				if (ct.indexOf('application/json') !== -1) {
					body = xhr.responseJSON || (function () { try { return JSON.parse(xhr.responseText || 'null'); } catch (e) { return null; } })();
				}
				var dbg = body && (body._debug || (body.data && body.data._debug));
				var success = body && body.success;
				var headerBadge = success ? badge('#16a34a') : badge('#dc2626');

				console.groupCollapsed(
					'%cPS-LABEL ajax%c ' + action + '  ' + (success ? '✔' : '✘') +
					'  ' + xhr.status + '  ' + (dur !== null ? dur + 'ms' : '') +
					(dbg && dbg.request_id ? '  rid=' + dbg.request_id : ''),
					headerBadge, ''
				);
				console.log('url:', url);
				console.log('request body:', data);
				console.log('response keys:', body ? Object.keys(body) : '<not json>');
				console.log('response head:', body || xhr.responseText.slice(0, 400));
				if (dbg && dbg.appended && dbg.appended.length) {
					console.groupCollapsed('appended trail (this request) · ' + dbg.appended.length);
					dbg.appended.forEach(printEntry);
					console.groupEnd();
				}
				if (dbg && dbg.trail && dbg.trail.length) {
					console.groupCollapsed('full order trail · ' + dbg.trail.length);
					dbg.trail.forEach(printEntry);
					console.groupEnd();
				}
				console.groupEnd();
			} catch (e) { console.warn('[PS-LABEL] ajaxComplete log failed:', e); }
		});
	}

	// ── 2. fetch() wrapper — some modules (iframe bridge, SPA admin) use native fetch ──
	if (typeof window.fetch === 'function' && !window.__ps_fetch_wrapped) {
		var origFetch = window.fetch.bind(window);
		window.__ps_fetch_wrapped = true;
		window.fetch = function (input, init) {
			var url = typeof input === 'string' ? input : (input && input.url) || '';
			// Only log our own endpoints — avoid flooding with WP core/analytics.
			var tracked = url.indexOf('parcselect_label_') !== -1 ||
				url.indexOf('/embed/label') !== -1 ||
				url.indexOf('/ps/v1/') !== -1;
			var isInternal = init && init.body instanceof FormData && init.body.get('_ps_debug_internal') === '1';
			if (!tracked || isInternal) {
				return origFetch(input, init);
			}
			var t0 = Date.now();
			return origFetch(input, init).then(function (resp) {
				var dur = Date.now() - t0;
				var ct  = (resp.headers.get('content-type') || '').toLowerCase();
				var src = resp.headers.get('x-ps-label-source') || '';
				var rid = resp.headers.get('x-ps-request-id') || '';
				var meta = { status: resp.status, dur: dur + 'ms', contentType: ct };
				if (src) meta.x_parcsepa_label_source = src;
				if (rid) meta.x_ps_request_id = rid;

				var preview = resp.clone();
				(ct.indexOf('application/json') !== -1 ? preview.json() : preview.text())
					.then(function (body) {
						console.groupCollapsed(
							'%cPS-LABEL fetch%c ' + (init && init.method ? init.method : 'GET') +
							'  ' + resp.status + '  ' + dur + 'ms  ' + shortUrl(url) +
							(src ? '  src=' + src : ''),
							(resp.ok ? badge('#16a34a') : badge('#dc2626')), ''
						);
						console.log('url:', url);
						console.log('headers:', meta);
						if (typeof body === 'string') {
							console.log('body head:', body.slice(0, 400));
						} else {
							console.log('body keys:', body ? Object.keys(body) : '<null>');
							console.log('body:', body);
						}
						console.groupEnd();
					})
					.catch(function () { /* body already consumed or not readable */ });
				return resp;
			}).catch(function (err) {
				console.log('%cPS-LABEL fetch%c ✘ NETWORK_ERROR  ' + shortUrl(url) + '  ' + (err && err.message),
					badge('#dc2626'), '');
				throw err;
			});
		};
	}

	function shortUrl(u) {
		try {
			var a = new URL(u, window.location.origin);
			return a.pathname + (a.search.length > 1 ? a.search.slice(0, 80) + (a.search.length > 80 ? '…' : '') : '');
		} catch (e) { return String(u).slice(0, 120); }
	}

	// ── 3. postMessage listener — VPS iframe can notify parent of state changes ──
	window.addEventListener('message', function (ev) {
		var origin = ev.origin || '';
		// Only log trusted origins we might embed.
		if (origin.indexOf('map.parcelselector.com') === -1 &&
			origin.indexOf('parcelselector.com') === -1) {
			return;
		}
		var body = ev.data;
		var type = (body && body.type) || '<untyped>';
		console.groupCollapsed('%cPS-LABEL postMessage%c ' + type + ' ← ' + origin,
			badge('#7c3aed'), '');
		console.log('origin:', origin);
		console.log('type:', type);
		console.log('data:', body);
		console.groupEnd();
	});

	// ── 4. Iframe inspector — log embedded VPS URL with parsed params ──
	function inspectIframes() {
		var iframes = document.querySelectorAll('#ps-label-wrap iframe, #etyk-step-payment iframe');
		if (!iframes || !iframes.length) return;
		iframes.forEach(function (f) {
			if (f.__ps_logged) return;
			f.__ps_logged = true;
			var src = f.src || '';
			var parsed = {};
			try {
				var u = new URL(src);
				u.searchParams.forEach(function (v, k) {
					// Truncate long receiver/sender fields to keep console readable.
					parsed[k] = v.length > 60 ? v.slice(0, 60) + '…' : v;
				});
			} catch (e) { parsed = { _parse_error: e.message }; }
			console.groupCollapsed('%cPS-LABEL iframe%c ' + (src.split('?')[0] || src),
				badge('#7c3aed'), '');
			console.log('src:', src);
			console.log('params:', parsed);
			console.log('sandbox:', f.sandbox ? Array.from(f.sandbox) : '<none>');
			console.log('allow:', f.allow || '<none>');
			console.groupEnd();
		});
	}
	// Poll for iframe appearance — ps-label-v2.js injects it on DOM ready.
	setInterval(inspectIframes, 1000);
	inspectIframes();

	// Prime trail poll, then loop.
	fetchTrail();
	setInterval(fetchTrail, pollMs);

	console.log(
		'%cPS-LABEL debug viewer%c 200%% diag armed · order=' + cfg.order_id +
		' · trail poll ' + pollMs + 'ms · wraps: jQuery.ajax + fetch + postMessage + iframe',
		badge('#16a34a'), ''
	);
})();
